Optimize Linux Boot Time with systemd-analyze: Profiling and Speeding Up Server Boot

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Context & Why

When a cloud instance reboots unexpectedly or you patch kernels across 50 nodes, waiting for SSH access costs real money. Every extra second of downtime matters. In autoscaling groups and failover clusters, slow server initialization delays health checks and leaves incoming traffic stranded.

Most modern Linux distributions run systemd under the hood. While systemd launches services concurrently—a massive upgrade over legacy SysVinit—default configurations accumulate bloat over time. Phantom network targets, storage timeouts, and unneeded background daemons easily turn a clean 8-second reboot into a 90-second crawl.

Stop guessing which service stalls your boot. Instead, rely on hard numbers. The built-in systemd-analyze tool profiles unit dependencies, exposes the bottleneck chain, and maps out exact resource consumers down to the millisecond.

Installation

Good news: systemd-analyze already ships with the base systemd package on almost every major distribution, including Ubuntu, Debian, AlmaLinux, Rocky Linux, and Fedora. You rarely need to install extra software.

Check whether the tool is available on your machine:

systemd-analyze --version

If you run a stripped-down container or a minimal cloud image that omitted auxiliary utilities, install the core package through your package manager.

On Debian and Ubuntu:

sudo apt update
sudo apt install -y systemd

On RHEL, AlmaLinux, and Rocky Linux:

sudo dnf install -y systemd

Configuration & Profiling

Tuning your boot timeline follows a four-step loop: measure baseline performance, identify true blockers, disable what you do not need, and verify.

1. Inspecting Overall Boot Time

Start by capturing a baseline metric from your last boot:

systemd-analyze time

You will see output broken into three distinct stages:

Startup finished in 5.120s (kernel) + 2.840s (initrd) + 21.430s (userspace) = 29.390s
graphical.target reached after 21.390s in userspace

The userspace metric reflects all services, daemons, and scripts loaded after the kernel hands off control. In this example, userspace consumed 21.4 seconds out of the total 29.4-second boot. That is where you have direct control and where you will find the easiest wins.

2. Pinpointing Slow Units with Blame

Next, list active units ranked by initialization time:

systemd-analyze blame | head -n 15

Typical server outputs highlight known culprits:

12.421s NetworkManager-wait-online.service
 8.114s cloud-init.service
 3.650s snapd.service
 2.102s apt-daily.service
 1.218s polkit.service

Do not panic yet. A service taking 12 seconds does not necessarily delay your boot by 12 seconds.

3. Tracing the Critical Chain

Because systemd starts services in parallel, independent background tasks run side-by-side without holding up user logins. To find the sequential chain that actually gates your server from reaching multi-user.target, trace the critical path:

systemd-analyze critical-chain multi-user.target

The resulting tree reveals when each dependent unit kicked off and how long it delayed the target:

multi-user.target @21.390s
└─nginx.service @20.120s +1.250s
  └─network-online.target @20.100s
    └─NetworkManager-wait-online.service @7.680s +12.420s
      └─NetworkManager.service @6.100s +1.580s

Look at the +12.420s entry on NetworkManager-wait-online.service. That single unit blocked network-online.target, delaying Nginx and extending boot time by over 12 seconds.

4. Generating an Interactive Boot Chart

Prefer a visual view? Render your entire startup sequence into a vector graphic:

systemd-analyze plot > /tmp/boot_analysis.svg

Open this SVG in any browser. It renders a clean waterfall timeline displaying CPU spikes, disk I/O activity, and exact start-to-finish execution bars for every running service.

5. Pruning and Masking Unnecessary Services

Once you identify candidate bottlenecks, eliminate them systematically.

Neutralizing NetworkManager-wait-online:
Many production servers get stuck on NetworkManager-wait-online.service. By default, it blocks progress until all network interfaces reach carrier state. If your server uses static IPs or standard cloud DHCP on eth0, mask this unit to shave 10 to 15 seconds off your boot instantly:

sudo systemctl disable NetworkManager-wait-online.service
sudo systemctl mask NetworkManager-wait-online.service

Freezing Cloud-Init on Provisioned Instances:
Cloud-init is essential on first boot to inject SSH keys and partition drives. On subsequent reboots, however, querying cloud metadata endpoints over HTTP adds 6 to 10 seconds of idle wait time. Once provisioning is complete, disable redundant checks:

# Skip cloud-init on future reboots
sudo touch /etc/cloud/cloud-init.disabled

On an Ubuntu 22.04 cloud node (2 vCPU, 4GB RAM), masking unused network waits and disabling cloud-init dropped total userspace startup from 21.4 seconds down to just 4.8 seconds.

Masking Peripheral and Desktop Services:
Headless cloud instances and rack-mounted servers never need Bluetooth radios, smart cards, or cellular modem services. Mask them completely so systemd refuses to launch them even as indirect dependencies:

sudo systemctl mask ModemManager.service
sudo systemctl mask bluetooth.service
sudo systemctl mask cups.service

6. Tightening Hung Service Timeouts

By default, systemd gives unresponsive services a 90-second grace period during boot or shutdown. If a background worker hangs, your entire reboot pauses for a minute and a half. Enforce a 15-second cutoff in /etc/systemd/system.conf:

sudo sed -i 's/#DefaultTimeoutStartSec=90s/DefaultTimeoutStartSec=15s/' /etc/systemd/system.conf
sudo sed -i 's/#DefaultTimeoutStopSec=90s/DefaultTimeoutStopSec=15s/' /etc/systemd/system.conf
sudo systemctl daemon-reload

Verification & Monitoring

Reboot your server to benchmark the improvements under live conditions:

sudo reboot

When the host reconnects, rerun systemd-analyze to compare against your baseline numbers:

systemd-analyze time

Check for unintended side effects. Make sure no dependent services failed because of a masked dependency:

systemctl --failed

Inspect the system journal for warnings or dependency cycles introduced during cleanup:

journalctl -b -p warning..err

Save a copy of your new boot plot before applying major kernel or distribution upgrades. Comparing historical SVG charts side-by-side catches rogue daemons before slow boot times reach production.

Share: