How to Optimize Battery Life on Fedora Laptops (TLP, power-profiles-daemon)

Install TLP and disable power-profiles-daemon to automatically optimize Fedora laptop battery life.

The battery drains faster than it should

You just finished a fresh Fedora install. The desktop looks clean, the terminal works, and you close the lid to take it to a coffee shop. Three hours later, the battery is at 12 percent. The system was idle. You were reading a book. The fan never spun up, but the power meter shows a steady 14 watts. Something is wrong. The kernel is leaving power-saving features disabled, and the desktop environment is not applying the right defaults for your hardware.

What is actually happening under the hood

Linux does not guess how to save power. It waits for instructions. Every laptop exposes a set of kernel interfaces that control CPU frequency scaling, PCIe Active State Power Management, USB autosuspend, NVMe power states, and disk spin-down. Without a manager, the kernel leaves most of these in a high-performance state to avoid breaking compatibility with older hardware or aggressive drivers. The default behavior prioritizes responsiveness over efficiency.

Fedora ships with power-profiles-daemon by default. It is a lightweight service designed to integrate with GNOME and KDE. It switches between three broad profiles: balanced, performance, and power-saver. It works well for most users. It does not touch low-level hardware quirks. It does not aggressively tune PCIe lanes or force USB devices into sleep when they are idle. It relies on the desktop environment to trigger profile changes when you plug in a charger or close the lid.

TLP takes a different approach. It is a command-line utility that applies a curated set of power-saving defaults at boot and on resume. It reads your hardware, applies conservative but effective settings, and leaves the system in a low-power state until you explicitly tell it otherwise. It does not rely on desktop environment integration. It runs in the background and manages the kernel interfaces directly. It writes to sysfs paths like /sys/bus/pci/devices/*/power/control and /sys/module/pcie_aspm/parameters/policy. It adjusts CPU governors through cpufreq. It toggles USB runtime power management through the usbcore module.

The problem appears when both services run at the same time. They fight over the same sysfs and procfs paths. One service sets a CPU governor to powersave. The other switches it back to schedutil thirty seconds later. USB autosuspend toggles on and off. The result is unpredictable power draw and occasional device disconnects. You must choose one. Running both creates a race condition that wastes more energy than it saves.

How to switch to TLP

Run these commands from a terminal with root privileges. The sequence disables the default daemon, installs TLP, and starts the new service.

sudo dnf install tlp tlp-rdw -y
# tlp-rdw adds support for Wake-on-Wireless and Bluetooth power management
sudo systemctl disable --now power-profiles-daemon
# --now stops the running service immediately and prevents it from starting on boot
sudo systemctl enable --now tlp
# Enables the TLP timer and starts the background daemon
sudo tlp start
# Forces an immediate application of the default power profile

TLP reads its configuration from /etc/tlp.conf. The file ships with sensible defaults. You do not need to edit it unless your hardware has specific quirks. The configuration uses a simple KEY=value format. Lines starting with # are comments. TLP applies settings at boot, when the lid closes, when the lid opens, and when the system resumes from suspend. It does not require a reboot to pick up changes. Run sudo tlp start after editing the config file.

Here is how to check whether the service is active and applying the correct profile.

systemctl status tlp
# Shows the service state, recent log lines, and the active timer
tlp stat
# Dumps the current power state, CPU governor, and PCIe ASPM settings

The tlp stat output will show AC or BAT at the top. It lists the active CPU frequency governor, the disk APM level, and whether USB autosuspend is enabled. If you see CPU: Intel P-state or CPU: AMD P-state, the kernel is handling frequency scaling directly. TLP will not override that. It will focus on PCIe, USB, and runtime power management instead.

Convention aside: config files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/. TLP follows this rule strictly. Put your overrides in /etc/tlp.d/. TLP merges configuration directories in order. Files in /etc/ always win. Manual edits in /usr/lib/ disappear on the next dnf upgrade --refresh.

Verify it worked

Close the lid. Wait thirty seconds. Open it. Run tlp stat again. The output should switch from AC to BAT. The CPU governor should reflect the battery profile. USB autosuspend should show enabled. If the system is plugged in, the settings revert to the AC profile automatically.

Check the actual power draw with powertop. It is not installed by default, but it gives you a real-time view of what is consuming energy.

sudo dnf install powertop -y
sudo powertop
# Runs an interactive power monitor. Press 'q' to exit.

Look at the Average power line at the top. An idle modern laptop should draw between 3 and 6 watts on battery. If it reads above 10 watts, something is preventing the system from entering low-power states. A stuck USB device, a misconfigured network interface, or a third-party kernel module can keep the CPU awake. Press t in powertop to toggle turbo boost off. Press i to toggle idle stats. These flags help you isolate whether the CPU is staying awake or a peripheral is polling constantly.

Run tlp status to see the active profile and the last time TLP applied settings. The output includes a timestamp. If the timestamp is older than your last lid close or resume, the systemd timer might not be firing. Check the timer with systemctl list-timers | grep tlp. The timer should show active and a remaining time of a few seconds. If it shows inactive, run sudo systemctl enable --now tlp.timer.

Common pitfalls and what the error looks like

TLP will not complain when it fails to apply a setting. It logs warnings to the journal. Run journalctl -xeu tlp to see what happened. The x flag adds explanatory text. The e flag jumps to the end. Most sysadmins type this muscle-memory style when a service misbehaves.

You might see a warning like USB autosuspend: failed to set autosuspend for device 1-1.2. This usually means a USB controller or a specific device does not support autosuspend. TLP skips it and continues. You can add the device ID to USB_DENYLIST in /etc/tlp.conf if it causes instability. The denylist uses a comma-separated format. Example: USB_DENYLIST="1-1.2 1-1.4".

Another frequent issue appears after a kernel update. TLP relies on sysfs paths that occasionally shift between kernel versions. If tlp stat shows PCIe ASPM: disabled when it should be power_supersave, the kernel module pcie_aspm might be missing or blocked by a boot parameter. Check your kernel command line with cat /proc/cmdline. If you see pcie_aspm=off, remove it from GRUB and regenerate the config. TLP cannot override explicit kernel boot parameters.

Network power management is another common friction point. Some Wi-Fi drivers disable power save when they detect a high packet loss rate. TLP tries to enable it anyway. If your connection drops every few minutes, add your interface to DEVICES_TO_DISABLE_POWER_SAVE_ON. The setting uses interface names like wlan0 or wlp2s0. Find your interface name with ip link.

Do not ignore SELinux denials. If TLP fails to write to a sysfs path, the denial shows up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. TLP ships with a proper policy module. If you see avc: denied, run sudo restorecon -Rv /sys/ and reboot. The security context might have drifted after a manual sysfs edit.

Reboot before you debug. Half the time the symptom is gone. Kernel modules reload cleanly, sysfs paths reset, and the timer rebinds to the correct hardware events.

When to use this vs alternatives

Use power-profiles-daemon when you want seamless desktop integration and do not need aggressive hardware tuning. Use TLP when you prioritize maximum battery life and are comfortable managing a command-line tool. Use auto-cpufreq when you want a daemon that dynamically switches governors based on real-time CPU load and thermal thresholds. Stick with the default Fedora setup when you run a desktop workstation that stays plugged in most of the time. Stay on the upstream Workstation if you only deviate from the defaults occasionally.

Where to go next