Job for ssh.service failed because the control process exited with error code

Run sudo sshd -t. It names the file and line that broke. Fix that line, then sudo systemctl reload ssh. Do this from a session you already have open, and read the warning below before you restart anything.

$ sudo sshd -t
/etc/ssh/sshd_config line 97: Directive 'UsePAM' is not allowed within a Match block

Before you touch sshd on a remote machine

This is the one service on this list that can lock you out of the server permanently. Your current SSH session survives a failed restart, because an established connection is handled by a forked child that keeps running after the parent dies. The danger is closing that session and discovering sshd never came back.

Three rules, in order of importance:

  1. Keep your existing session open. Do not log out until you have confirmed a new connection works. Open a second terminal and connect again as the test, rather than reconnecting with the only session you have.
  2. Always run sshd -t before restarting. It costs nothing and catches the majority of causes below.
  3. Prefer reload over restart. A reload re-reads the configuration without dropping the listening socket, so a mistake leaves the working daemon running.

If the machine has a serial or provider console, confirm you can reach it before changing sshd_config at all. That console is the difference between a two minute fix and a rebuild.

The causes, in order of how often they appear

  1. A directive in the wrong place. Most sshd_config options are only valid at the top level, and a surprising number of guides show them being added at the end of a file that already contains a Match block. Everything after a Match line belongs to that block until the next one, so an option appended to the bottom of the file silently lands inside it. UsePAM, PermitRootLogin and Port are the usual casualties. Move the directive above the first Match.
  2. Missing privilege separation directory. The error is Missing privilege separation directory: /run/sshd. Because /run is a tmpfs it is empty after every boot, so this appears on reboot even though nothing was edited. Creating it by hand works until the next restart; the durable fix is a tmpfiles rule:
    echo 'd /run/sshd 0755 root root -' | sudo tee /etc/tmpfiles.d/sshd.conf
    sudo systemd-tmpfiles --create
  3. Host keys missing or unreadable. sshd will not start without them. Regenerate on Debian and Ubuntu with sudo dpkg-reconfigure openssh-server, or on any distribution with sudo ssh-keygen -A. Note that replacing host keys makes every existing client warn about a changed fingerprint, so only do this if the keys are genuinely gone.
  4. Port 22 already bound. Usually a stale sshd that survived a bad shutdown, or socket activation already holding the port:
    sudo ss -tlnp | grep ':22 '
    systemctl status ssh.socket

    On recent Ubuntu, ssh.socket may own the port instead of ssh.service. If socket activation is enabled, the Port directive in sshd_config is ignored entirely and the listening port is set in the socket unit instead. This surprises people who change the port and see no effect.

  5. SELinux blocking a non-standard port. On RHEL, Rocky and Alma, moving sshd off port 22 fails until SELinux is told: sudo semanage port -a -t ssh_port_t -p tcp 2222.

Reading the exit code

status=255 is sshd’s own general failure code and normally means a configuration problem, so run sshd -t. status=1/FAILURE covers most other startup rejections. status=226/NAMESPACE points at a unit drop-in with sandboxing directives rather than at sshd_config at all: inspect it with systemctl cat ssh. The full table is in the nginx version of this error.

How to stop it happening again

sudo sshd -t && sudo systemctl reload ssh

Make that one line a habit and this error stops being frightening. The test exits non-zero on a bad configuration, so the reload never runs against a file that would take the daemon down. For a change you are genuinely unsure about, start a second sshd on a spare port first, confirm you can log in on it, and only then edit the real one.

Related

I changed Port in sshd_config and nothing happened

Socket activation. On recent Ubuntu releases ssh.socket owns the listening port and sshd_config‘s Port directive is ignored. Edit the socket unit instead with sudo systemctl edit ssh.socket, set ListenStream= to clear the default and then to your port, and restart ssh.socket. Check which applies with systemctl status ssh.socket.

sshd -t passes but the service still will not start

Then it is not the configuration file. The remaining candidates are the privilege separation directory, missing host keys, the port being held by something else, and a unit drop-in. Run sudo journalctl -xeu ssh.service --no-pager | tail -40 and read the last lines before the exit: all four of those name themselves clearly in the journal.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *