A machine that used to boot in seconds and now takes minutes is a job for systemd-analyze, not guesswork. You will measure the current boot, find units that took time to start, follow the dependency chain that held up the default target, and check a unit file before installing it. You will also see a safe way to inspect a service's systemd security settings. Allow about 15 minutes. These commands inspect state; none of them restart services or change unit files.
This guide is written against systemd 255.4-1ubuntu8.17, reported by the installed Ubuntu package on this machine. The command syntax comes from the installed systemd-analyze(1) manual page. Check your own version first, because newer or older systemd releases add and drop commands and options.
$ systemd-analyze --version
systemd 255 (255.4-1ubuntu8.17)
Use --no-pager in scripts and in copy-and-paste checks. Without it, longer output can open a pager and leave your terminal waiting. To see the available verbs and options, run:
$ systemd-analyze --no-pager --help
Checkpoint: you know which systemd release you are measuring, and your terminal is not stuck inside less.
Run the default command, or spell out time. With no verb given, systemd-analyze implies time.
$ systemd-analyze --no-pager time
Startup finished in 4.916s (kernel) + 16min 52.838s (userspace) = 16min 57.754s
graphical.target reached after 16min 52.817s in userspace.
These numbers are not a promise the desktop was fully usable, or that every disk operation had finished. They measure the path to the point where systemd has spawned the relevant services, and report when the target was reached. A slow userspace value is a reason to investigate, not proof one service is solely responsible.
If you are comparing hosts, record the target and all three components together. A container may skip a separate initrd measurement, while a physical machine often reports all three: kernel, initrd and userspace.
blame lists running units in descending order of the time systemd measured while they were activating.
$ systemd-analyze --no-pager blame | head -12
6h 9.455s mdcheck_start.service
49min 2.964s chkrootkit.service
59.897s systemd-networkd-wait-online.service
30.137s certbot.service
24.757s containerd.service
The top line is a lead, not a verdict. A unit can look slow because it waits on another unit, and the command does not show time spent waiting in the job queue. It also does not measure services with Type=simple usefully, because systemd treats them as started immediately. Device units can jump straight to active without an activating phase too.
Do not disable a service just because it sits near the top. Work out what depends on it first, and whether the delay is expected, such as a filesystem check or a network-online wait.
Use critical-chain to see the time-critical tree for the default target. The value after @ is when a unit became active relative to boot. The value after + is its measured activation time.
$ systemd-analyze --no-pager critical-chain
graphical.target @16min 52.817s
`-multi-user.target @16min 52.817s
`-basic.target @22.035s
`-systemd-resolved.service @21.457s +489ms
The exact tree depends on the host. Compare it with blame: a slow unit outside the critical chain may not delay the target at all, while a modest delay inside the chain can matter a lot. You can also inspect a particular target or service by naming it:
$ systemd-analyze --no-pager critical-chain graphical.target
These timings still do not expose every job timeout or every delay from parallel unit execution, so treat them as a map for the next check rather than the final word.
verify checks unit files and reports parse errors, missing dependencies and other problems, without installing or activating the file. Point it at the path you are preparing. Elevated privileges are not normally needed to validate a readable file.
$ systemd-analyze --no-pager verify /path/to/example.service
$ printf 'exit status: %s\n' "$?"
exit status: 0
A zero status means the verification command succeeded. Warnings can still deserve attention, especially when a referenced executable, user or dependency is absent. Test the exact file that will be deployed, not a hand-edited copy sitting in another directory.
Warning: if you later install a unit under /etc/systemd/system, that is a state-changing operation and normally needs root. Validate first, keep the previous file as a backup, then ask systemd to reload its configuration with sudo systemctl daemon-reload. Do not start or enable an untested service as part of this guide. To undo a staged file, restore the backup or remove only the new file, then run sudo systemctl daemon-reload again.
The security verb reviews a unit's sandboxing and privilege-related settings. It prints individual checks and an overall exposure score. That score is not a universal security certification: a low or high exposure value needs context about what the service actually does and what access it genuinely requires.
$ systemd-analyze --no-pager security cron.service
NAME DESCRIPTION EXPOSURE
`- User=/DynamicUser= Service runs as root user 0.4
`- PrivateDevices= Service potentially has access to hardware devices 0.2
Use the output to choose questions for the unit maintainer: does the service really need root, hardware access or unrestricted namespaces, before you touch its unit. Hardening settings can break a service outright, so do not paste suggested options into production without testing and a rollback plan.
For a timer expression, calendar normalises the expression and shows the next occurrence. Quote expressions that contain spaces or shell metacharacters.
$ systemd-analyze --no-pager calendar 'Mon *-*-01 09:00:00'
Normalized form: Mon *-*-01 09:00:00
Next elapse: Mon 2027-02-01 09:00:00 GMT
The next date is relative to the current clock, so it will differ on another day or host. For configuration discovery, unit-paths prints the directories systemd searches. cat-config can show a configuration file and its drop-ins, but a missing file is an ordinary result on systems that do not provide that configuration.
$ systemd-analyze --no-pager unit-paths
$ systemd-analyze --no-pager cat-config system.conf
Read the search path before assuming which copy of a unit is active. A file in /etc/systemd/system generally takes precedence over the packaged copy, which is why local overrides deserve a careful look.
--no-pager for reproducible output.time gave you the kernel, initrd and userspace figures.blame with critical-chain before blaming or disabling a unit.verify ran against the exact unit file you intend to deploy.security as an investigation aid, not an automatic hardening recipe.