Troubleshooting

Fix "Job for service failed" when a systemd service won't start

Diagnose systemd services that fail to start: read status and journal output, decode exit codes like 203/EXEC and 217/USER, test configs, and fix restart loops.

IntermediateLinux VPS3 min read

Job for nginx.service failed because the control process exited with error code. See "systemctl status nginx.service" and "journalctl -xeu nginx.service" for details. systemd is telling you exactly where to look. This guide shows how to read that output and fix the usual causes when a systemd service fails to start.

Before you start

  • Root access and the service name.

Read the status and the journal

systemctl status myapp --no-pager -l
journalctl -u myapp -n 50 --no-pager

The status shows the Main PID exit code and the last log lines; the journal shows the full error from the program itself. For services with their own log files (Nginx, MySQL), check those too.

Decode the exit status

StatusMeaningTypical fix
status=1/FAILUREThe program exited with an errorRead its message in the journal
status=203/EXECExecStart could not be executedWrong path, not executable, missing shebang or CRLF line endings
status=217/USERThe User= account does not existCreate the user or fix the name
status=200/CHDIRWorkingDirectory missing or inaccessibleCreate it or fix permissions
status=226/NAMESPACEA sandboxing path (ReadWritePaths etc.) does not existCreate the path or adjust hardening options
status=9/KILLKilled, often by the OOM killerCheck dmesg for out-of-memory
status=143 / 15/TERMStopped by a signal, often normal on stopCheck for timeouts

Test the program's own configuration

Most daemons can check their config without starting:

  • Nginx: nginx -t
  • Apache: apachectl configtest
  • PHP-FPM: php-fpm8.3 -t
  • SSH: sshd -t
  • HAProxy: haproxy -c -f /etc/haproxy/haproxy.cfg

Port already in use

bind() to 0.0.0.0:80 failed (98: Address already in use)

Find the other process with ss -ltnp 'sport = :80' and stop it, or change one of the ports.

Run the command by hand

Copy the ExecStart line (see it with systemctl cat myapp) and run it as the service user, in the working directory, with its environment:

sudo -u myapp bash -c 'cd /srv/myapp && set -a && . ./.env && set +a && ./start.sh'

Errors that were hidden in the service appear directly in your terminal.

After editing unit files

Always reload systemd, otherwise it keeps using the old version:

systemctl daemon-reload && systemctl restart myapp

Prefer systemctl edit myapp for changes to packaged services; it creates an override that survives package updates.

Start request repeated too quickly

A service that crashes on start and has Restart=always hits the start limit and stops trying. Fix the underlying error, then clear the counter:

systemctl reset-failed myapp && systemctl start myapp

Add RestartSec=5 so restarts are spaced out.

Timeouts

start operation timed out means the service did not report readiness in time (default 90 s). Either startup is slow (database recovery, migrations) or the Type= is wrong: a program that stays in the foreground needs Type=simple, not forking. Raise TimeoutStartSec if startup is legitimately slow.

Systemd failures FAQ

How do I see all failed services?

systemctl --failed lists them.

Why does it work from the shell but not as a service?

Different user, working directory, PATH and environment. Make each explicit in the unit file.

Does a failed service start again after reboot?

If it is enabled, systemd tries again at boot. Fix it so it does not fail again.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.