Tune thermald Safely with Thermal Zones and XML Trips
A laptop that throttles too early usually means thermald is ignoring the configuration you think it reads. This guide shows which control mode your installed daemon actually uses, how to read the thermal devices Linux exposes, and how to prepare a narrowly scoped thermal-conf.xml rule. Examples target thermald 2.5.6, shipped here as Ubuntu package 2.5.6-2ubuntu0.24.04.5. Allow about 20 minutes, longer if you still need to identify a fan or sensor before changing anything.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you change anything
You need a shell account with systemctl, journalctl, and read access to /sys/class/thermal. Reading those paths is unprivileged; editing /etc/thermald and restarting the daemon need sudo. Keep a root shell out of the copy-and-paste block until a step explicitly calls for it.
Warning
Thermal control is a genuine safety boundary. A bad trip temperature can throttle a machine too early, let it run hotter than intended, or trigger an unexpected shutdown. Do not replace a vendor critical limit just to silence a warning, and do not write directly to a cooling device while the daemon is running. Collect the current configuration and take a backup before you edit anything.
1. Confirm the installed daemon and service mode
Start with version and service information:
thermald --version
systemctl status thermald --no-pager --lines=12
systemctl cat thermald
Checkpoint
The version command should print a version. On the install used for this guide, the service runs /usr/sbin/thermald --systemd --dbus-enable --adaptive. --systemd keeps the process inside systemd's service model, while --adaptive selects adaptive tables when available and ignores XML configuration entirely. This distinction matters: creating thermal-conf.xml changes nothing for a service already running in adaptive mode.
If the service is inactive, check the recent reason before starting it:
journalctl -u thermald -b --no-pager --lines=40
Do not launch a second copy of thermald while the system service is active. Two controllers competing for the same thermal sysfs devices is a genuinely bad time.
2. Inspect the sensors and cooling devices
The daemon discovers thermal sensors and cooling drivers under /sys/class/thermal. List their names and read the values that are safe to inspect:
for zone in /sys/class/thermal/thermal_zone*; do
printf '%s: ' "$zone"
sed -n '1p' "$zone/type"
printf ' temperature: '
sed -n '1p' "$zone/temp"
done
for device in /sys/class/thermal/cooling_device*; do
printf '%s: ' "$device"
sed -n '1p' "$device/type"
printf ' state: '
sed -n '1p' "$device/cur_state"
printf ' maximum: '
sed -n '1p' "$device/max_state"
done
A temperature reading such as 36500 means 36.5 degrees Celsius: the kernel interface reports thousandths of a degree. Confirm what a sensor actually is from its type; never assume thermal_zone0 is the CPU. Cooling device state ranges are device-specific, so never copy a target state from one machine onto another.
Checkpoint
Write down the exact zone type, sensor type and cooling-device type you plan to connect. If you cannot pin down all three, stop at inspection. The default daemon may already be doing the right thing.
3. Understand which XML file would be selected
In non-adaptive mode, thermald checks these files in order and uses the first one it finds:
/etc/thermald/thermal-conf.xml.auto/var/run/thermald/thermal-conf.xml.auto/etc/thermald/thermal-conf.xml
A path passed with --config-file overrides that search and the defaults get ignored entirely. In adaptive mode, the manpage says XML configuration is ignored outright, so reordering the search changes nothing visible. Check the actual service command again after any package or distribution update, since the unit file decides the effective mode.
4. Create a small passive trip
Only do this once you have confirmed the service actually runs in XML mode and you know the platform's sensor names. What follows is a template: replace every value marked REPLACE_.... It requests passive CPU cooling at 80 degrees Celsius, written as 80000 because XML temperatures here are thousandths of a degree.
<?xml version="1.0"?>
<ThermalConfiguration>
<Platform>
<Name>REPLACE_PLATFORM_NAME</Name>
<ProductName>*</ProductName>
<Preference>QUIET</Preference>
<ThermalZones>
<ThermalZone>
<Type>REPLACE_ZONE_TYPE</Type>
<TripPoints>
<TripPoint>
<SensorType>REPLACE_SENSOR_TYPE</SensorType>
<Temperature>80000</Temperature>
<type>passive</type>
</TripPoint>
</TripPoints>
</ThermalZone>
</ThermalZones>
</Platform>
</ThermalConfiguration>
QUIET selects passive cooling in this configuration model. The format can also describe active cooling, cooling-device order, target states, sampling periods and PID parameters, but those are hardware-specific. Add one relationship at a time, and never paste a fan path, device index or PID constant from an online example without matching it to this machine's actual sysfs devices.
Validate the XML before it gets anywhere near the service. This only checks syntax; it proves nothing about whether the zone and sensor names actually exist:
xmllint --noout /etc/thermald/thermal-conf.xml
Warning
Back up the existing file before replacing it, and keep the old copy around for recovery:
sudo install -D -m 0644 /etc/thermald/thermal-conf.xml \
/etc/thermald/thermal-conf.xml.before-thermald-guide
sudoedit /etc/thermald/thermal-conf.xml
If the file does not exist yet, that backup command fails harmlessly. A missing file is not permission to drop an unverified configuration straight into place.
5. Apply and verify a configuration change
Reload the service only after the syntax check and the backup both succeed:
sudo systemctl restart thermald
systemctl is-active thermald
journalctl -u thermald -b --no-pager --lines=30
Checkpoint
systemctl is-active should print active, and the journal should show no XML parse error. Confirm the daemon's process mode again with systemctl cat thermald, then re-read the relevant zone and cooling-device files. A successful restart proves the service started, nothing more: it does not prove a trip is correctly matched or has ever fired.
If the service fails or behaves unexpectedly, restore the saved file and restart:
sudo cp -- /etc/thermald/thermal-conf.xml.before-thermald-guide \
/etc/thermald/thermal-conf.xml
sudo systemctl restart thermald
systemctl is-active thermald
If you created a new file and there was no previous configuration, move it out of the search path instead of deleting it outright:
sudo mv -- /etc/thermald/thermal-conf.xml \
/etc/thermald/thermal-conf.xml.disabled
sudo systemctl restart thermald
Common traps
- XML appears to do nothing. The service may be running with
--adaptive, which always wins over XML. Check the unit'sExecStart. - The wrong file got edited. An auto-generated file can be selected before
/etc/thermald/thermal-conf.xml. Check all three documented paths. - Polling got disabled.
--poll-interval 0only works when the available sensors can report temperature changes asynchronously. - Performance changed unexpectedly.
--disable-active-powerturns off active power management and can leave the system with lower power limits. It is not a general troubleshooting switch. - A critical trip got waved away.
--ignore-critical-tripcan dodge a shutdown for a critical point set too low. Treat that as a temporary diagnostic move, never a safety improvement.
Done means
- Recorded the baseline. You noted the installed thermald version and its effective service arguments.
- Identified the hardware. You found the relevant thermal zone and cooling-device types from sysfs.
- Checked the mode. You know whether adaptive mode is ignoring your XML file.
- Kept changes small and reversible. Any XML change was backed up, syntax-checked and deliberately narrow.
- Verified the result. The service is active and its journal shows no new configuration error.