Run systemctl status SERVICE -l --no-pager and journalctl -xeu SERVICE --no-pager. The exit status and the last log lines usually name the cause: bad configuration, a missing binary or user, a port already in use, permissions or SELinux, or an unmet dependency.
Step 1: read what systemd tells you
$ systemctl status httpd -l --no-pager $ journalctl -xeu httpd --no-pager | tail -40 $ systemctl cat httpd # the unit as systemd sees it, including drop-ins
httpd.service - The Apache HTTP Server Active: failed (Result: exit-code) since Tue 2026-10-01 02:14:09 IST Process: 2210 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND (code=exited, status=1/FAILURE) Main PID: 2210 (code=exited, status=1/FAILURE) httpd[2210]: AH00072: make_sock: could not bind to address [::]:80
Step 2: match the symptom
| What you see | Likely cause | Check |
|---|---|---|
status=1/FAILURE and an application error in the log | Configuration error | Test the config: httpd -t, nginx -t, sshd -t, named-checkconf |
| “could not bind”, “Address already in use” | Port taken by another process | ss -ltnp | grep :80 |
status=203/EXEC | ExecStart binary missing, wrong path or not executable | ls -l the path, check systemctl cat |
status=217/USER or 216/GROUP | User or group in the unit does not exist | id USER |
status=200/CHDIR | WorkingDirectory missing | Create it or fix the unit |
| “Permission denied” but modes look right | SELinux | ausearch -m avc -ts recent |
Result: timeout | Slow start or Type mismatch (Type=notify vs simple) | Raise TimeoutStartSec, check the unit type |
Result: start-limit-hit | Restarted too often too fast | Fix the cause, then systemctl reset-failed SERVICE |
| “Dependency failed” | A required unit or mount is down | systemctl list-dependencies SERVICE |
Step 3: fix and verify
# after editing a unit file or drop-in $ sudo systemctl daemon-reload $ sudo systemctl reset-failed SERVICE $ sudo systemctl start SERVICE $ systemctl is-active SERVICE; systemctl is-enabled SERVICE # make it start at boot and now $ sudo systemctl enable --now SERVICE
If the cause is an SELinux label, restore it instead of disabling SELinux:
$ ls -lZ /path/to/file $ sudo restorecon -Rv /path/to/dir $ sudo semanage port -l | grep http # non-standard port? add it with semanage port -a
setenforce 0 switches SELinux to permissive until reboot. It is useful for a quick test to see whether SELinux is the cause, but do not leave it that way: fix the label or boolean and switch back with setenforce 1.
Starts by hand but not at boot
- It is not enabled:
systemctl enable SERVICE. - It starts before something it needs (network, a mount, a database). Add
After=andRequires=ornetwork-online.target. - A mount in
/etc/fstabis slow or failing. Checksystemctl --failedandfindmnt --verify.
Common mistakes
- Looking only at
systemctl statusand not at the journal. - Editing
/usr/lib/systemd/system/*.servicedirectly; usesystemctl edit SERVICE(drop-ins survive updates). - Forgetting
daemon-reloadafter changing a unit. - Disabling SELinux or the firewall to “make it work”.
Production considerations
Validate configuration before restarting a live service (-t options), keep a copy of the working config, and test changes on one node of a load-balanced pool first. Record the root cause so the next on-call engineer does not repeat the search.
Interview questions
A service fails after reboot but starts manually. Why?
Typical causes: not enabled, ordering or dependency problems (network or mounts not ready), a failing fstab mount, or an environment difference between your shell and systemd. Check journalctl -b -u SERVICE and systemctl list-dependencies.
What does status=203/EXEC mean?
systemd could not execute the ExecStart command: wrong path, missing file, or no execute permission (or an SELinux denial).
More: Managing services and daemons · systemd chapter · Troubleshooting SELinux denials.