Edit sshd_config on the wrong session and you can lock yourself out of the only way in. sshd itself gives you the way to avoid that: check the configuration, inspect exactly what applies to one login, and only then reload. Allow about fifteen minutes. You need read access to the configuration; changing it or restarting SSH needs elevated privileges.
The examples match OpenSSH 9.6p1 from Ubuntu package openssh-server 1:9.6p1-3ubuntu13.19. Options and packaged defaults differ on other releases, so check the installed binary before trusting an example blind.
Run these ordinary, read-only checks:
$ command -v sshd
/usr/sbin/sshd
$ sshd -V
OpenSSH_9.6p1 Ubuntu-3ubuntu13.19, OpenSSL 3.0.13 30 Jan 2024
$ dpkg-query -W -f='${Package} ${Version}\n' openssh-server
openssh-server 1:9.6p1-3ubuntu13.19
Your package string will differ off Ubuntu. The daemon reads /etc/ssh/sshd_config by default, and the Ubuntu package includes matching files from /etc/ssh/sshd_config.d/ in lexical order. Keep that directory in mind the moment a setting seems to ignore the line you just edited.
Before changing anything, ask the daemon to parse the configuration and sanity-check its keys:
$ sudo sshd -t
$ printf 'sshd test status: %s\n' "$?"
sshd test status: 0
-t never starts a listener. Status 0 means the configuration and keys passed. Anything else is a stop sign: read the diagnostic, fix one issue at a time, and rerun the command. A complaint about a missing or unreadable host key means go inspect that path and its ownership, not generate a replacement on the spot.
sudo appears here because host private keys are normally root-readable only. If your account can already read every required file, you may not need it, and either way this command changes nothing.
Checkpoint: do not reload until sudo sshd -t returns status 0.
Use extended test mode to see what the daemon will actually use, not what the file merely suggests:
$ sudo sshd -T | grep -E '^(port|listenaddress|hostkey|usepam|pubkeyauthentication|passwordauthentication|permitrootlogin|authorizedkeysfile|subsystem) '
port 22
listenaddress [::]:22
listenaddress 0.0.0.0:22
hostkey /etc/ssh/ssh_host_rsa_key
hostkey /etc/ssh/ssh_host_ecdsa_key
hostkey /etc/ssh/ssh_host_ed25519_key
usepam yes
pubkeyauthentication yes
passwordauthentication yes
permitrootlogin yes
authorizedkeysfile .ssh/authorized_keys .ssh/authorized_keys2
subsystem sftp /usr/lib/openssh/sftp-server
Exact lines depend on this host and its included files. -T prints the effective configuration and exits, applying nothing. Do not mistake the file's commented-out examples for active settings, and remember OpenSSH keeps the first value it finds for many options, so an earlier included file can quietly win over a later one.
The command above filters for readability. To review everything, save the output somewhere outside the SSH configuration directory, or just page through it:
$ sudo sshd -T | less
Global output is not enough once the file has Match blocks. Supply the connection details that select the rule:
$ sudo sshd -T -C user=deploy,addr=203.0.113.25,host=server.example,laddr=192.0.2.10,lport=22 | grep -E '^(allow|deny|passwordauthentication|pubkeyauthentication|permittty|forcecommand|authenticationmethods)'
allowagentforwarding yes
allowtcpforwarding yes
passwordauthentication no
permittty yes
pubkeyauthentication yes
Swap in the actual user and addresses you are checking. The -C values are connection parameters for conditional configuration, not a request to connect anywhere, and leaving one out can mean a conditional rule never gets selected at all. Compare this against the global -T result before touching authentication settings.
A common trap: testing only an interactive administrator login while a deployment account is actually governed by a later Match User block. Always test the account and source network the change is meant to affect, not the one that is easiest to test.
Public-key login normally reads .ssh/authorized_keys relative to the user's home directory. Check the path and permissions as the target user without printing any private key material:
$ namei -l /home/DEPLOY_USER/.ssh/authorized_keys
$ test -r /home/DEPLOY_USER/.ssh/authorized_keys && echo readable
readable
Replace DEPLOY_USER. The daemon's StrictModes checks can reject an otherwise valid key when the home directory, .ssh directory or key file is writable by someone unexpected. Use sshd -T to confirm the configured authorizedkeysfile path rather than assuming every install uses the same list.
Diffie-Hellman Group Exchange uses /etc/ssh/moduli, a seven-field text file of tested prime records the daemon picks a suitable modulus from. Check it is present and sample a few records:
$ sudo test -s /etc/ssh/moduli && echo 'moduli file is non-empty'
moduli file is non-empty
$ sudo awk 'NF == 7 { print $1, $2, $3, $4, $5; count++; if (count == 3) exit }' /etc/ssh/moduli
20200101000000 2 4 2048 2
20200101000000 2 4 3072 2
20200101000000 2 4 4096 2
Timestamps and values on your host will differ. Never hand-edit this file or drop in an untested candidate. The documented workflow generates candidates and screens them for primality with ssh-keygen -M generate and ssh-keygen -M screen, a separate maintenance job, not a prerequisite for an ordinary reload.
Changing authentication, listening addresses or root access can interrupt service or lock people out. Before editing, keep an existing administrative session open and arrange a second way into the machine, such as console access. Then back up the configuration before touching it:
$ sudo cp --preserve=mode,ownership,timestamps /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
$ sudoedit /etc/ssh/sshd_config
sudoedit runs the editor as your normal user, which is worth using out of habit. Make one focused change, save, then rerun the test:
$ sudo sshd -t
$ sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin|port) '
passwordauthentication no
permitrootlogin prohibit-password
port 22
Not every installation needs a restart for every change. This host may use systemd socket activation, where a port or listen-address change also needs the socket unit reloaded. Check the service arrangement before doing anything disruptive:
$ systemctl is-enabled ssh.socket 2>/dev/null || true
$ systemctl is-active ssh.service ssh.socket 2>/dev/null || true
Reloading asks the running daemon to reread its configuration. It can affect new connections and is still a service operation, so keep elevated privileges and your current session open:
$ sudo systemctl reload ssh
$ systemctl is-active ssh
active
If this system uses socket activation and you changed Port, AddressFamily or ListenAddress, follow the packaged service instructions and regenerate the socket state before restarting the socket. Do not restart blind while your only way in is the SSH connection you are testing.
If the new configuration is wrong, restore the backup and validate again before reloading:
$ sudo cp --preserve=mode,ownership,timestamps /etc/ssh/sshd_config.bak /etc/ssh/sshd_config
$ sudo sshd -t
$ sudo systemctl reload ssh
That backup command restores only the main file. Changed an included file under /etc/ssh/sshd_config.d/ too? Undo that one separately. Do not delete the backup until a fresh login has succeeded and you no longer need the recovery path.
sshd -t returns status 0 after the final edit.sshd -T shows the intended values.sshd -T -C shows the intended values for each important case./etc/ssh/moduli are present and readable.