Step 1: make sure you have another way in
Log in as a normal user with your key, in a window you keep open, and check that sudo works:
ssh user@server
sudo -v
If you have no such account yet, see how to create an SSH user with sudo. Do this first. It is the only step that protects you from a lockout.
Step 2: look for settings already there
sudo grep -ri permitrootlogin /etc/ssh/sshd_config /etc/ssh/sshd_config.d/
For most sshd settings, the first value read wins, not the last. On Debian and Ubuntu, sshd_config has Include /etc/ssh/sshd_config.d/*.conf near the top, so files there are read first, in name order. In our test, with 00-cloud.conf saying PermitRootLogin yes and 10-no-root.conf saying no, root stayed allowed.
A hosting provider's image may place a file like that, so remove or change any such line. Without an Include line, edit PermitRootLogin in sshd_config itself.
Step 3: add the setting
echo 'PermitRootLogin no' | sudo tee /etc/ssh/sshd_config.d/10-no-root.conf
Step 4: check before you reload
sudo sshd -t
sudo sshd -T | grep -i permitrootlogin
sshd -t prints nothing when all is well. A typo gets a message like unsupported option "maybe", and you should fix it before going on. sshd -T shows the value the server will really use:
permitrootlogin no
Step 5: reload
# Debian and Ubuntu
sudo systemctl reload ssh
# Red Hat, Fedora and similar
sudo systemctl reload sshd
A reload applies to new connections, and your open session carries on. We confirmed this: a session opened before the change kept running, and a new login followed the new rule.
Step 6: test from a new window
ssh root@server
You should see Permission denied, even with the correct key. The server log says:
ROOT LOGIN REFUSED FROM 203.0.113.10 port 41288
Then log in as your normal user from another new window, and run sudo -v again.
What each value does
| Value | Password | Key | Key with a forced command |
|---|---|---|---|
yes | Allowed | Allowed | Allowed |
prohibit-password | Refused | Allowed | Allowed |
forced-commands-only | Refused | Refused | Allowed |
no | Refused | Refused | Refused |
The default is prohibit-password, since OpenSSH 7.0. So on a system that has not changed it, root cannot log in with a password, but a root key still works. without-password is an old name for the same value. sshd -T printed without-password on our OpenSSH 10.0 server when the setting was prohibit-password. Version 10.1 changed it to print the current name.
A forced command means command="..." in authorized_keys. forced-commands-only suits a backup job that really needs root for one fixed command.
Exceptions with Match
To allow root keys only from one management address, add this to the same file, below the first line:
Match Address 203.0.113.10
PermitRootLogin prohibit-password
Plain sshd -T does not show the effect of a Match block. Use -C to describe a connection and see what would apply. These two gave different answers in our test:
sudo sshd -T -C user=root,host=server,addr=203.0.113.10 | grep -i permitrootlogin
sudo sshd -T -C user=root,host=server,addr=198.51.100.7 | grep -i permitrootlogin
If you do get locked out
Use the console from your hosting provider, which does not go through SSH. Delete the file you added and reload sshd.
Questions
What is the difference between PermitRootLogin no and prohibit-password?
no refuses root in every way. prohibit-password, the default, refuses root's password but still accepts a root key.
Does reloading sshd close my open session?
No. A reload applies to new connections, and sessions already open carry on.
What if I get locked out after disabling root login?
Use your hosting provider's web console, which does not go through SSH. Delete the file you added and reload sshd.