When an Ubuntu upgrade gets interrupted, the usual advice, and suggested by the OS, is simple: run sudo dpkg --configure -a. But what happens when that command appears to hang indefinitely on a completely unrelated package? That is exactly what happened on one of my Ubuntu servers. An interrupted SSH session left the package manager in an incomplete state, and the recovery command appeared to get stuck while configuring power-profiles-daemon. It turned out that power-profiles-daemon wasn't actually the problem. The package configuration was waiting for systemd, which was itself waiting for another service that had been stuck for hours.

The initial problem

The server was being upgraded normally with:
sudo apt update && sudo apt upgrade
APT reported:
E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.
That is a normal message after an interrupted package operation, so the obvious next step was:
sudo dpkg --configure -a
However, it stopped at:
Setting up power-profiles-daemon (0.21-1ubuntu2) ...
Waiting did not appear to help. Restarting the server had also not resolved the issue, and attempts to restart power-profiles-daemon manually appeared to hang as well.

Don't assume the package shown on screen is the problem

The package where the output stops, is not necessarily the package causing the problem. The first useful step was to look at the processes involved while dpkg was still running:
ps aux | grep -E 'dpkg|power-profiles' | grep -v grep
This revealed a much more interesting chain:
dpkg --configure -a
  └─ /var/lib/dpkg/info/power-profiles-daemon.postinst
       └─ deb-systemd-invoke restart power-profiles-daemon.service
            └─ systemctl --quiet --system restart power-profiles-daemon.service
So dpkg itself wasn't doing some mysterious operation on the package. Its post-installation script was asking systemd to restart the service, and systemctl was waiting.

Check whether the daemon itself is actually broken

Before modifying anything, I tested the daemon directly rather than going through systemd:
sudo timeout 10 /usr/libexec/power-profiles-daemon -vv
The daemon successfully initialised:
Core           Starting power-profiles-daemon version 0.21
Core           Name 'net.hadess.PowerProfiles' acquired
Core           Name 'org.freedesktop.UPower.PowerProfiles' acquired
Core           Handling driver 'fake'
Core           Handling driver 'platform_profile'
Core           Handling driver 'intel_pstate'
Core           Handling driver 'amd_pstate'
Core           Handling driver 'placeholder'
Core           Driver 'placeholder' loaded
Core           Setting active profile 'balanced' for reason 'reset'
There were messages about unavailable hardware-specific drivers, but nothing indicating that the daemon itself was stuck or crashing. The most important part here; the executable worked when launched directly.

Look at what systemd is waiting for

"What is systemd waiting for?" While dpkg was still stuck, I checked systemd's active jobs:
systemctl list-jobs
The result contained:
JOB UNIT                                 TYPE  STATE
58  setvtrgb.service                     start waiting
147 systemd-update-utmp-runlevel.service start waiting
135 system-getty.slice                   start waiting
233 power-profiles-daemon.service        start waiting
141 plymouth-quit-wait.service           start running
2   multi-user.target                    start waiting
1   graphical.target                     start waiting
Eureka. This was the breakthrough. power-profiles-daemon.service was waiting, but so was multi-user.target. And multi-user.target was being held up by another part of the systemd transaction.

The real culprit: plymouth-quit-wait.service

I inspected the service that was still actively starting:
systemctl status plymouth-quit-wait.service --no-pager -l
The result showed that Plymouth had been waiting for the boot process to finish for more than three hours:
● plymouth-quit-wait.service - Hold until boot process finishes up
     Loaded: loaded (/usr/lib/systemd/system/plymouth-quit-wait.service; static)
     Active: activating (start) since Tue 2026-08-18 15:03:31 CEST; 3h 33min ago
   Main PID: 1340 (plymouth)
     └─1340 /usr/bin/plymouth --wait
Plymouth had been waiting for the boot process to finish for more than three hours. That explained the entire chain:
dpkg
  │
  └─ power-profiles-daemon.postinst
       │
       └─ systemctl restart power-profiles-daemon.service
            │
            └─ systemd job waiting
                 │
                 └─ multi-user.target
                      │
                      └─ plymouth-quit-wait.service
                           │
                           └─ plymouth --wait

Fixing the blocked systemd transaction

Since Plymouth was the component actually stuck in the boot transaction, I told it to quit:
sudo plymouth quit
This immediately allowed the systemd dependency chain to continue. The important part here is that I didn't manually edit the dpkg database, delete package locks, or force the package into a configured state. I fixed the obstacle that was actually preventing systemd from completing its job. The already-running dpkg --configure -a operation could then continue normally.

Useful commands when dpkg appears frozen

These are good first diagnostic commands when dpkg --configure -a appears to hang:
# See what dpkg and its child processes are doing
ps aux | grep -E 'dpkg|apt|deb-systemd|systemctl' | grep -v grep

# See systemd's current jobs
systemctl list-jobs

# Inspect a suspicious service
systemctl status SERVICE_NAME --no-pager -l

# See the service's systemd properties
systemctl show SERVICE_NAME \
  -p ActiveState \
  -p SubState \
  -p MainPID \
  -p Job \
  -p Result

# Inspect recent boot/service messages
sudo journalctl -b --no-pager -n 100

The takeaway

When dpkg --configure -a appears to freeze, resist the temptation to immediately kill it or start deleting lock files. Find out what it is waiting for. In my case, the screen appeared to blame power-profiles-daemon. The daemon itself was fine. Its package configuration was waiting for systemctl, systemd was waiting for multi-user.target, and the target was being held up by a plymouth --wait process that had been stuck for hours. Once the actual blocker was identified and Plymouth was allowed to quit, the package manager could continue normally. When something appears frozen, trace the dependency chain rather than trusting the last line printed on the screen.