How to set up SSH key login and turn off password login

You want to log in to a Linux server over SSH with a key instead of a password, and then make the server refuse passwords altogether. A key cannot be guessed over the network the way a password can, so this closes off the most common way into an exposed SSH service. This article takes you through it in an order that cannot lock you out, provided you follow the order.

Do not close your working session. Keep one logged-in SSH session open from the first step to the last. Every change to the server is made from it, and it is how you undo a mistake. Switching password login off before you have proved the key works is how people lose access to their own servers. Make sure you also know how to reach the server console (hypervisor, cloud provider web console, KVM or a keyboard and screen) before you start.

Applies to: a Linux server running OpenSSH (sshd), and clients on Linux, macOS or Windows 10 and 11 using the built-in OpenSSH client. Commands on the server need root or sudo. Names in the examples (user, server) are placeholders.

What is going on

SSH can prove who you are in several ways. With a key pair you keep a private key on your machine and put the matching public key on the server in ~/.ssh/authorized_keys. The server sends a challenge that only the private key can answer, so the secret never crosses the network. The private key should itself be protected by a passphrase, so a stolen laptop or backup does not hand over the server.

Setting up a key does not by itself turn passwords off. Until you change the server configuration, sshd still accepts both. Turning passwords off is a separate step, and it has two settings, not one, because password-style prompts can also arrive through KbdInteractiveAuthentication. On servers that use PAM, the sshd_config manual says keyboard-interactive usually serves the same role as password authentication, so you disable one or the other. Setting both to no is the clear way to do it.

Before you start / check first

1. Have a way back in

Keep your current session open, and find the out-of-band route to the console now, not after you need it. If you are about to disable passwords on a cloud VM, open its serial or web console once and make sure you can log in there. That route does not use SSH, so it still works if sshd is misconfigured.

2. Check the server version and what is already set

ssh -V
sudo sshd -T | grep -Ei '^(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|permitrootlogin|authenticationmethods)'

sshd -T prints the effective configuration after all files are read, which is what the server will really do. pubkeyauthentication yes is the default and should already be on. The setting name KbdInteractiveAuthentication was introduced in OpenSSH 8.7, with ChallengeResponseAuthentication kept as a deprecated alias, so on an older server use the old name or check which one sshd -T prints. The Include keyword used in step 5 needs OpenSSH 8.2 or later.

3. Know which service name you have

The service is called ssh on Debian and Ubuntu, and sshd on RHEL, Fedora, Arch and most others. Try systemctl status ssh and systemctl status sshd; one of them will exist.

Why this works

Public key authentication and password authentication are independent switches in sshd. Once the key is installed and tested, the password switches have nothing left to protect, and turning them off removes the attack surface that brute-force scripts rely on. The order below matters: key first, test, then lock the door.

The fix

Step 1. Make a key pair on your own machine

The same command works in a Linux or macOS terminal and in PowerShell or Command Prompt on Windows 10 and 11. Ed25519 is the OpenSSH default for new keys and is small and fast.

ssh-keygen -t ed25519 -C "karl@laptop"

Accept the default file name unless you manage several keys, and type a passphrase when asked. In the test, this created id_ed25519 (private) and id_ed25519.pub (public) and printed the key fingerprint. Never copy the private key to the server. Only the .pub file goes there. On Windows the files are in C:\Users\<you>\.ssh\.

Step 2. Install the public key on the server

Linux and macOS. ssh-copy-id logs in once with your password and appends the key to the remote ~/.ssh/authorized_keys, creating the file and directory if needed. Add -p 2222 if the server uses another port.

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server

Windows client. Microsoft’s documentation does not use ssh-copy-id on Windows. Copy the file across with scp from PowerShell, then append it on the server:

scp $env:USERPROFILE\.ssh\id_ed25519.pub user@server:laptop.pub

# then, logged in to the server:
mkdir -p ~/.ssh
cat ~/laptop.pub >> ~/.ssh/authorized_keys
rm ~/laptop.pub

By hand, any client. If ssh-copy-id is not available, paste the single line from the .pub file into ~/.ssh/authorized_keys on the server. Either way, the permissions must be right, or sshd silently ignores the key. Run this on the server as the user the key is for:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod go-w ~
PathModeWhy
~ (home directory)not writable by group or othersAnyone who can write there can swap the .ssh directory.
~/.ssh700Only you may read or change it.
~/.ssh/authorized_keys600Only you may change which keys are accepted.

These checks come from the StrictModes setting, which is on by default: sshd checks file modes and ownership of the user’s files and home directory before accepting a login. In the test, a authorized_keys set to mode 666 was refused and the server log said Authentication refused: bad ownership or modes for file ..., while the client only saw Permission denied (publickey). If the key is ignored, read the server log (journalctl -u ssh or journalctl -u sshd, or /var/log/auth.log or /var/log/secure). On a server with SELinux enforcing, a wrongly labelled ~/.ssh can also cause this [UNCONFIRMED: not tested here; restorecon -R ~/.ssh is the usual repair].

Step 3. Test the key from a second session

Open a new terminal window. Do not use the one that is logged in. Force it to use the key only, so a fallback to a password cannot hide a failure:

ssh -o PreferredAuthentications=publickey user@server

You should be asked for the key’s passphrase (not the account password) and then be logged in. If you are asked for a password or told Permission denied (publickey), stop. Add -v to see which keys the client offers, and look at the server log. Do not go on until this works. You still have the original session, so nothing is lost.

Step 4. Load the key into an agent so you type the passphrase once

ssh-agent holds the unlocked key in memory for your login session. On Linux and macOS:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l

Many desktops already run an agent, in which case ssh-add is all you need. ssh-add -l lists the loaded keys. In the test, ssh-add accepted the passphrase and listed the key. [UNCONFIRMED: logging in through the agent did not work in the sandbox used for testing, so agent-based login is not verified here. Passphrase login was.]

Windows. The ssh-agent service is disabled by default. From an elevated PowerShell prompt (the commands are Microsoft’s):

Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
Get-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519

Get-Service should report Running. Microsoft also points out that a remote session opened with a key has no stored user credentials, so it cannot authenticate onward to other machines as you. That is by design.

Step 5. Turn off password login on the server

From your first, still-open session. First look at what is already configured, including the include directory:

grep -rn -iE '^\s*(Include|PasswordAuthentication|KbdInteractiveAuthentication|ChallengeResponseAuthentication|PermitRootLogin|UsePAM)' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/

The first value wins, and another file can override you. The sshd_config manual says: “for each keyword, the first obtained value will be used.” Most current distributions put Include /etc/ssh/sshd_config.d/*.conf near the top of /etc/ssh/sshd_config, and the files in that directory are read in lexical (alphabetical) order before the lines below the Include. A drop-in such as 50-cloud-init.conf on a cloud image that says PasswordAuthentication yes then beats a PasswordAuthentication no you add to the main file. In the test, with an Include first and a drop-in saying yes, sshd -T reported passwordauthentication yes even though the main file said no; with the line placed before the Include it reported no. Never trust the file you edited, check sshd -T. Which drop-ins exist on your distribution or cloud image varies, so look in the directory.

The cleanest fix is your own drop-in with a name that sorts before the others, so yours is read first. Back up first, then create it:

sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudoedit /etc/ssh/sshd_config.d/00-keys-only.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no

If your sshd_config has no Include line (older systems), put those three lines in /etc/ssh/sshd_config itself, replacing any existing lines for the same keywords rather than adding duplicates. If an existing PasswordAuthentication yes sits in the main file above the Include, remove or change that line, since it would win.

Root login. The default for PermitRootLogin is prohibit-password, which means root can still log in with a key. no blocks root over SSH entirely, so you log in as a normal user and use sudo. Only set it if you have a working non-root user with sudo rights, and test sudo in your second session first.

Step 6. Validate, check the effective values, reload

sudo sshd -t

sshd -t checks the configuration and the host keys and prints nothing when everything is fine. If it prints an error, fix it and do not reload. In the test, a misspelt option gave Bad configuration option: PasswordAuthentcation and exit status 255, and a correct file gave no output and status 0. Then confirm what the server will actually do:

sudo sshd -T | grep -Ei '^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin|pubkeyauthentication)'

You want passwordauthentication no, kbdinteractiveauthentication no, permitrootlogin no and pubkeyauthentication yes. If passwordauthentication still says yes, another file is overriding you: go back to the grep above. When the values are right, reload the service (a reload makes sshd re-read its config without restarting it):

# Debian, Ubuntu
sudo systemctl reload ssh

# RHEL, Rocky, Alma, Fedora, Arch, SUSE
sudo systemctl reload sshd

Use whichever name exists on your system. Ubuntu 22.10 and later start sshd through systemd socket activation (ssh.socket). That mainly matters for changing the listening port; for authentication settings a reload of the ssh service is what to run, and the test in step 7 will show whether it took effect [UNCONFIRMED: socket-activation behaviour was not tested here and is not covered in the OpenSSH manual pages, which are the source for the rest of this article].

Step 7. Test from a third session

Open another new terminal and check both halves. Key login must work:

ssh -o PreferredAuthentications=publickey user@server

And a password attempt must be refused without being offered a password prompt:

ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password,keyboard-interactive user@server

The second command should end with Permission denied (publickey). In the test it did, and it never reached a password prompt. Only now is it safe to close the old sessions.

Verification

  • sudo sshd -T shows passwordauthentication no, kbdinteractiveauthentication no and pubkeyauthentication yes.
  • A fresh session with your key and passphrase logs in.
  • A fresh session with PubkeyAuthentication=no ends in Permission denied (publickey).
  • Other users and scripts that used passwords have been moved to keys, or they are now locked out. Check before you leave.
  • The server log (journalctl -u ssh or -u sshd) shows Accepted publickey for ... for your login.

If you locked yourself out

If you still have the original session open, use it. Undo the change from there, then validate and reload as above. The steps below are for when every SSH session is gone.

  1. Open the server console that does not rely on SSH: the hypervisor console, the cloud provider’s web or serial console, a KVM, or the physical keyboard and screen. A key-only cloud account may have no local password, so check this before you start. If it does not, use the provider’s recovery or rescue-mode feature.
  2. Log in there, and remove your drop-in, or set PasswordAuthentication yes again:
sudo rm /etc/ssh/sshd_config.d/00-keys-only.conf
sudo sshd -t && sudo systemctl reload ssh     # or sshd
  1. Connect over SSH with the password, find out why the key failed (permissions, wrong user, wrong key, a drop-in overriding you, the key never copied), fix it, and repeat from step 3.
  2. If you edited the main file instead, restore the backup you made: sudo cp -a /etc/ssh/sshd_config.bak /etc/ssh/sshd_config, then sudo sshd -t and reload.

Notes

  • Related: the first time you connect after a rebuild, ssh may refuse with a host key warning. That is covered in the article “SSH: WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!” in this knowledge base.
  • Protect the private key. The passphrase is the second factor: whoever has the file but not the passphrase cannot use it. Back the key up somewhere safe. If you lose it and passwords are off, you are relying on console access.
  • One key per person and device. Add each public key as a separate line in authorized_keys. To revoke a device, delete its line.
  • Leave a window open when you change anything about SSH later, including the port, AllowUsers or AuthenticationMethods. The same rule applies every time.
  • Windows servers. This article is about a Linux server. On Windows Server, keys for administrators go in C:\ProgramData\ssh\administrators_authorized_keys with a restricted ACL, see the Microsoft link below.
  • Sources: sshd_config (https://man.openbsd.org/sshd_config), ssh-keygen (https://man.openbsd.org/ssh-keygen), sshd (https://man.openbsd.org/sshd), OpenSSH 8.2 release notes (https://www.openssh.org/txt/release-8.2) and 8.7 release notes (https://www.openssh.org/txt/release-8.7), OpenSSH key management on Windows (https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement). man ssh-copy-id on your own system covers its options.

Stuck at a step? Post what you ran and the exact message (hide anything private) in The Patch Panel and we will work through it. The best answer earns points on Top of the Stack.

Was this helpful?

Updated on October 14, 2026