sshd_config over SSH with one worry in the back of their mind: if I restart sshd now, will it kick me off the server? So they delay the restart, or run it and wait for the terminal to freeze. On a typical Linux server, restarting sshd leaves your current session alone. The real danger shows up later, when you close that session and find the new config refuses every login, including yours.
That gap between "the restart went fine" and "nobody can log in anymore" is where most self-inflicted SSH lockouts come from. It is worth understanding why, because the fix is a habit, not a tool.
Why your current session survives a restart
sshd-session binary, but the idea is the same in older versions.
When you restart the service, systemd stops the main listener and starts a new one. Whether your session processes get killed along the way depends on the unit's KillMode setting. The ssh units shipped by the common distributions typically use KillMode=process, which tells systemd to stop only the main process and leave the per-connection children running. Your shell keeps working because the process serving it was never touched.
You can see this structure for yourself:
BASH
# How systemd stops the service (unit is 'ssh' on Debian/Ubuntu, 'sshd' on RHEL family)
systemctl show -p KillMode ssh
# Listener vs per-connection processes, shown as a tree
ps -ef --forest | grep '[s]shd'
# Read the unit file, including any ExecStartPre or ExecReload checks
systemctl cat sshKillMode=control-group would kill the whole process group. And a blunt command like pkill sshd matches the session processes too, not just the listener. But a normal systemctl restart on a stock unit is not what drops people.
What a broken config actually does
systemctl restart command may print an error, but it is easy to miss, and some people run it chained with other commands. Meanwhile every new connection gets refused. Your current session is now the only way into the server, and it is held together by your Wi-Fi, your laptop's sleep settings, and any idle timeout like ClientAliveInterval that you may have just configured.
Some distributions guard against part of this. Their unit files run sshd -t before a start or reload, so a syntax error aborts the reload and the old listener stays up. That protection depends on the unit, so read it with systemctl cat instead of assuming. And it only helps with reload in most cases. On a restart, the old listener is already gone by the time the check fails.
The second kind of broken config is harder to spot because it is perfectly valid. sshd starts, the port is open, and you still cannot get in. Common examples during hardening:
PasswordAuthentication noset before your public key is actually in~/.ssh/authorized_keyswith the right permissions.PermitRootLogin noon a server where you only ever log in as root.AllowUsersorAllowGroupsadded without your own account in the list.- A new
Portvalue with the firewall, or SELinux on RHEL-family systems, still only allowing 22.
Include /etc/ssh/sshd_config.d/*.conf near the top of the main file, and for most keywords sshd uses the first value it reads. A drop-in from cloud-init or a provider image can quietly override the setting you just changed further down. A common pattern in lockout and "my hardening didn't apply" tickets is exactly this: the admin edited the right line in the wrong place.
Validate the config before you restart
sshd -t is test mode. It parses the full config, including Include files, checks the host keys, and exits without starting anything. It prints nothing when the config is valid, so pair it with an explicit success message. Run it as root, because it needs to read the host keys.
sshd -T goes further and prints the effective configuration after defaults and drop-ins are applied. That is how you catch the first-value-wins problem: you see what sshd will actually use, not what you think you wrote. Adding -C lets you evaluate Match blocks for a specific user and source address.
BASH
# Syntax and host key check; silent with exit code 0 when valid
sudo sshd -t && echo 'config OK'
# Effective values after defaults and Include files are applied
sudo sshd -T | grep -Ei '^(port|permitrootlogin|passwordauthentication|pubkeyauthentication|allowusers|allowgroups) '
# Evaluate Match blocks for a given user and client address
sudo sshd -T -C user=deploy,host=example.com,addr=203.0.113.10 | grep -i '^passwordauthentication'sshd -t points at the file and line. Illustrative output format:
TEXT
/etc/ssh/sshd_config: line 42: Bad configuration option: PermitRootLogn
/etc/ssh/sshd_config: terminating, 1 bad configuration optionsauthorized_keys, whether the firewall allows the new port, whether SELinux labels it, or whether your username matches AllowUsers. A config can pass sshd -t and still lock you out. That is why the next step matters more.
Prove it with a second session before closing the first
- Keep your current session open. Ideally open a second one before you change anything, so you have a spare if the first drops.
- Back up the file first, for example to
sshd_config.baknext to the original, so a revert is one copy away. - Make the change, then run
sshd -tand check the relevant values withsshd -T. - Apply it. Prefer a reload if your unit supports it, since many units validate before reloading and keep the old listener on failure. Restart works too, as long as step 3 passed.
- From a new terminal, start a brand new SSH connection using the same user, key, and port you will rely on later. Adding
-vto the ssh client shows which authentication methods the server offers and where it fails. - In that new session, confirm that
sudoor your root access still works. A login that succeeds but cannot escalate is still a lockout for admin work. - Only after the new login works, close the old session.
The habit that prevents the lockout
sshd -t to catch syntax errors, use sshd -T to see what sshd will actually enforce, and treat a successful fresh login in a second terminal as the only real confirmation. Close the original session last, never first.