---
title: How to set up SSH key login and turn off password login
description: Replace SSH passwords with a key pair, prove the key works from a second session, and only then switch password login off on the server. Covers Linux, macOS and Windows clients, the sshd_config.d trap where another file overrides you, and how to get back in if you lock yourself out.
url: "https://keh-tech.net/kb/ssh-key-login-disable-passwords/"
updated: "2026-10-15"
category: "How-to"
tags:
  - Hardening
  - Linux
  - OpenSSH
  - Security
  - SSH
---

# 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.sshid_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 ~
```

| Path | Mode | Why |
| --- | --- | --- |
| `~` (home directory) | not writable by group or others | Anyone who can write there can swap the .ssh directory. |
| `~/.ssh` | 700 | Only you may read or change it. |
| `~/.ssh/authorized_keys` | 600 | Only 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.sshid_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:ProgramDatasshadministrators_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](/community/help/) and we will work through it. The best answer earns points on [Top of the Stack](/leaderboard/).
