Skip to main content
DevOps Insightsguides & answers

SSH · troubleshooting

Permission denied (publickey)

The server tried every key your client offered and accepted none, and that one line covers several unrelated problems. The key is not in authorized_keys, the wrong user, file permissions sshd refuses to trust, a private key ssh refused to read, or the right key never offered at all — and the client cannot tell them apart. ssh -v on your side and the server's auth log on the other can.

Reproduced on OpenSSH 10.3, . Where the text says “reproduced”, the behaviour was run on that version, not taken from documentation.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 9 sections

Before you start

  • The user and host you are connecting to, and the key you expect to be used. ssh -G <host> prints the settings ssh will apply after reading your config, including user and identityfile.
  • The public half of that key (the .pub file) and its fingerprint from ssh-keygen -lf.
  • A second way into the server before you change anything there: an open session, another authorized key, or the provider's console.
  • On the server: sudo or the target account, to read sshd's log and to fix ownership and modes on the home directory, ~/.ssh and authorized_keys.
  • For a Git host: access to the account settings that list which SSH keys are registered.

Run this first

step 1 of 3
ssh -v USER@HOST 2>&1 | grep -E 'Offering public key|Server accepts key|Authentications that can continue|UNPROTECTED|No more authentication methods'

Look for Your key never offered, or an UNPROTECTED warning: the client. Your key offered and no Server accepts key: the server.

Shows which keys the client offered, in order, and whether the server accepted any. It is the only view of the client's side of the negotiation.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

Does ssh -v print "UNPROTECTED PRIVATE KEY FILE"?

Cause space

5 of 5 still possible

  • The key you offer is not in that user's authorized_keysCommon
  • You are logging in as the wrong userCommon
  • sshd does not trust the permissions on ~/.ssh or authorized_keysCommon
  • ssh refused to read your private keyOccasional
  • The right key is never offeredOccasional

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    ssh -v USER@HOST 2>&1 | grep -E 'Offering public key|Server accepts key|Authentications that can continue|UNPROTECTED|No more authentication methods'

    Shows which keys the client offered, in order, and whether the server accepted any. It is the only view of the client's side of the negotiation.

    Look for Your key never offered, or an UNPROTECTED warning: the client. Your key offered and no Server accepts key: the server.

  2. Step 2

    sudo journalctl -u ssh --since '-15 min' | grep -E 'Failed publickey|Invalid user|bad ownership or modes|not allowed'

    The server's log names the check that failed. The unit is ssh on Ubuntu and Debian and sshd on most other distributions; /var/log/auth.log holds the same lines where rsyslog writes it.

    Look for Invalid user (wrong user), bad ownership or modes (permissions), Failed publickey with a fingerprint and no Authentication refused line just before it (key not authorized)

  3. Step 3

    ls -ld ~ ~/.ssh ~/.ssh/authorized_keys

    On the server, as the target user — the StrictModes check, done by eye.

    Look for No group or world write on any of the three, and the user as owner

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

The key you offer is not in that user's authorized_keys

Common

The public key was never added, was added for a different user or a different server, or a new key pair was generated and the old public key is still the one installed. The server compares fingerprints and finds no match. Its log says Failed publickey, with the fingerprint of the key it refused — which is the fastest way to see which key the client really sent.

Confirm

ssh-keygen -lf ~/.ssh/id_ed25519.pub

The fingerprint, to compare with the SHA256 value in the server's Failed publickey line and with ssh-keygen -lf ~/.ssh/authorized_keys run on the server

Fix

  • Append the public key — the .pub file, never the private one — to ~/.ssh/authorized_keys of the user you log in as, through a path you still have: another admin, a second key, or the provider's console.
  • Make sure it is one line, complete, and not wrapped by a copy-paste.

You are logging in as the wrong user

Common

Keys are authorized per user. Logging in as a user that does not exist, or as root on a host that only lets a named user in, fails with the same message. Reproduced: a non-existent user produced Invalid user in the server log and plain Permission denied on the client. On cloud images the login user is set by the image, so the right name is in the image's documentation, not guessed.

Confirm

ssh -v USER@HOST 2>&1 | grep -E 'Authenticating to|Offering public key'

The user the client is actually authenticating as — a Host block or default can change it from what you typed in your head

Fix

  • Log in as the user whose authorized_keys holds your key, then use sudo for administrative work.
  • Pin it per host in ~/.ssh/config with a User line, so a default username never decides it for you.

sshd does not trust the permissions on ~/.ssh or authorized_keys

Common

With StrictModes on — the default — sshd ignores an authorized_keys file, or the directories above it, that is writable by anyone but its owner, or owned by an account other than the user or root. Reproduced with both a group-writable authorized_keys and a group-writable directory above it: the key was in the file and was still refused, logged as Authentication refused: bad ownership or modes.

Confirm

ls -ld ~ ~/.ssh ~/.ssh/authorized_keys

Run on the server as that user: no group or world write bit on any of them, and the user as owner

Fix

  • chmod 700 ~/.ssh and chmod 600 ~/.ssh/authorized_keys, owned by the user; the home directory must not be group- or world-writable either.
  • Do not turn StrictModes off to get in. It exists to stop someone else from adding a key to your account.
sudo chown -R <user>: /home/<user>/.ssh
sudo chmod 700 /home/<user>/.ssh
sudo chmod 600 /home/<user>/.ssh/authorized_keys

Run on the server by an account with sudo: a user cannot take back files another account owns. If the user already owns them, the two chmod commands work without sudo.

ssh refused to read your private key

Occasional

A private key file readable by other users is ignored, loudly: Permissions 0644 for 'KEY' are too open and This private key will be ignored. The public key can still reach the server: for an OpenSSH-format key, sshd logged Accepted key ... found at <path>/authorized_keys:1 and Postponed publickey, then the connection closed with no Accepted publickey. Reproduced, the warning appears only when ssh reads the file itself; if the agent already holds the key, the agent's copy is used.

Confirm

ls -l ~/.ssh/id_ed25519

-rw------- (600). Anything readable by group or others is refused.

Fix

  • chmod 600 the private key. The .pub file can stay readable.

The right key is never offered

Occasional

ssh offers the keys it knows about in order (agent keys first, with those matching a configured IdentityFile ahead of the rest, then configured key files the agent does not hold), and the server allows only so many attempts per connection: MaxAuthTries, 6 by default. A different default key file, a key that is not loaded, or an agent full of other keys can mean the right one is never reached. Reproduced on OpenSSH 10.3: with seven unrelated keys in the agent ahead of the right one and no -i, the server disconnected after six failures with Too many authentication failures; with -i KEY -o IdentitiesOnly=yes it succeeded. OpenSSH's manual describes IdentitiesOnly as using only the configured identity files even if the agent offers more.

Confirm

ssh -v USER@HOST 2>&1 | grep 'Offering public key'

Whether the key you meant appears at all, and how many others are offered before it

Fix

  • Name the key and stop the agent from adding others: ssh -i ~/.ssh/KEY -o IdentitiesOnly=yes USER@HOST.
  • Make it permanent with a Host block in ~/.ssh/config: IdentityFile ~/.ssh/KEY and IdentitiesOnly yes.
ssh -i ~/.ssh/KEY -o IdentitiesOnly=yes USER@HOST

If this works and the plain command does not, the problem was which keys were offered, not the key itself.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

Your computer offered the server one or more keys to prove who you are, and the server accepted none of them. The message does not say why: the key may not be on the server, the username may be wrong, the server may distrust the permissions on its key file, or the right key may never have been offered. ssh -v on your side and the server's log on the other side tell you which.

A key the server has never seen

Reproduced with OpenSSH 10.3 (OpenSSH_10.3p1) on macOS: a non-root sshd -D -e on 127.0.0.1:2222 (loopback) with its own host key and a config in a scratch folder: AuthorizedKeysFile pointing at a file with one public key, passwords off, StrictModes no because the scratch folder sits under the world-writable /tmp, and PerSourcePenalties no so repeated test failures were not throttled. The client config Host lab set the address, port and user, IdentityAgent none and IdentitiesOnly yes, and the client offered a key that was not authorized. The user name and key fingerprint are replaced with placeholders.

Command

ssh -v -F client_config -i wrong_key lab true 2>&1 | grep -E 'Authenticating to|Offering public key|Server accepts key|Authentications that can continue|No more authentication|Permission denied'

Output

debug1: Authenticating to 127.0.0.1:2222 as '<user>'
debug1: Authentications that can continue: publickey
debug1: Offering public key: wrong_key ED25519 SHA256:<fingerprint> explicit
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
<user>@127.0.0.1: Permission denied (publickey).

sshd log for the same attempt:
Connection from 127.0.0.1 port 57429 on 127.0.0.1 port 2222
Failed publickey for <user> from 127.0.0.1 port 57429 ssh2: ED25519 SHA256:<fingerprint>
Connection closed by authenticating user <user> 127.0.0.1 port 57429 [preauth]

How to read it

  • Authenticating to ... as '<user>' is the account whose authorized_keys the server checks. A non-existent user (tested as nosuchuser) gave exactly the same client output; only the server's Invalid user nosuchuser from 127.0.0.1 told them apart.
  • Offering public key names the key file and its fingerprint. No Server accepts key follows, so the server looked the key up and did not find it.
  • (publickey) is the list of methods the server still allows, not a reason. Here it is the only method, because the test server had passwords turned off.
  • The server's Failed publickey line carries the same fingerprint as the client's offer, which is how you match the two logs. In the permission tests, sshd logged Authentication refused: bad ownership or modes for file (or for directory) and then its own Failed publickey, so read the line above it too.
  • With the authorized key, the client printed Server accepts key and Authenticated to 127.0.0.1 ([127.0.0.1]:2222) using "publickey"., and sshd logged Accepted publickey for <user>.

Words used on this page

Key pair
A private key that stays on your machine and a public key (.pub) that you give to servers. A server only ever needs the public half.
authorized_keys
The file, by default ~/.ssh/authorized_keys of the user you log in as, that lists the public keys allowed to log in as that user.
Fingerprint
A short hash of a public key, such as SHA256:..., printed by ssh-keygen -lf, by ssh -v and in the server's log. Matching fingerprints is how you tell which key was used.
ssh-agent
A background program that holds unlocked private keys. ssh offers the agent's keys before key files the agent does not hold.
StrictModes
An sshd setting, on by default, that makes sshd ignore authorized_keys when the file, or a directory above it up to your home, is writable by other users or owned by someone other than you or root.
MaxAuthTries
The number of authentication attempts sshd allows per connection, 6 by default. Every key offered counts as one.
IdentitiesOnly
An ssh setting that makes it offer only the key files you configured, even if the agent holds others.
What is actually happening

Public-key login is a negotiation. The client offers public keys one at a time; the server checks each against the authorized_keys of the user you are logging in as, and either accepts one or replies with the methods that can still continue. When nothing is accepted, the client prints Permission denied, and the word in brackets is that list of methods — here, only publickey.

So the message says nothing about why. Reproduced against a throwaway OpenSSH 10.3 server: a key missing from authorized_keys, a user that does not exist, an authorized_keys file that was group-writable, and a group-writable directory above it all produced exactly the same client output. The server's log separated every one of them — Failed publickey, Invalid user, and Authentication refused: bad ownership or modes for the file or for the directory.

Two causes are entirely on the client. A private key file that other users can read is refused: WARNING: UNPROTECTED PRIVATE KEY FILE! and This private key will be ignored. The refusal can come late. When ssh can get the public key without the private file, from a .pub beside it or from a key in OpenSSH's own format, it offers that key first, the server accepts it, and only the signing step fails. Reproduced, ssh only says so when it reads the file itself — a key the ssh-agent already held was used from the agent regardless. And the right key may never be offered: with seven unrelated keys in the agent ahead of it and no -i, the server disconnected with Too many authentication failures rather than Permission denied, and naming the key with -i and IdentitiesOnly=yes made it work.

StrictModes is why permissions matter on the server. OpenSSH's manual says sshd checks the modes and ownership of the user's files and home directory before accepting a login, because people accidentally leave them writable, and it is on by default. A key that is in the file is still refused if someone other than its owner could have put it there.

How to tell this is your problem
WhereWhat you see
sshuser@host: Permission denied (publickey).
git push / clone over SSHgit@github.com: Permission denied (publickey). — the same check, run by the Git host
ssh, during authenticationWARNING: UNPROTECTED PRIVATE KEY FILE! ... This private key will be ignored.
sshReceived disconnect from HOST port 22:2: Too many authentication failures — the right key was never reached
server auth logAuthentication refused: bad ownership or modes for file /home/USER/.ssh/authorized_keys
server auth logFailed publickey for USER from ADDRESS — or — Invalid user USER from ADDRESS

How to know it is actually fixed

  • ssh -v shows Server accepts key and prints Authenticated to HOST ([ADDRESS]:PORT) using "publickey"..
  • The server log shows Accepted publickey for USER with the fingerprint you expected.
  • It also works with the agent out of the way — ssh -o IdentityAgent=none -i KEY USER@HOST — so it does not depend on what the agent happens to hold.

Stopping it happening again

  • Give each host a Host block in ~/.ssh/config with User, IdentityFile and IdentitiesOnly yes.
  • Keep private keys at 600 and ~/.ssh at 700; fix permissions rather than switching StrictModes off.
  • Before changing authorized_keys or sshd settings on a server, keep a second way in open — a working session, a second key, or the provider's console. A reload of sshd does not close existing sessions, so test from a new one.

Security considerations

  • Only the .pub half goes to a server or a Git host. If a private key was ever pasted into a ticket, a chat or someone's authorized_keys, make a new pair and remove the old public key everywhere it is installed.
  • Do not switch StrictModes off to get in. sshd(8) gives the reason: if authorized_keys, ~/.ssh or the home directory is writable by other users, someone else could add their own key and log in as you.
  • Trying key after key has a cost. Every key ssh offers shows that server your public key, and current sshd's default PerSourcePenalties refuse connections from an address for a time after failed logins (this test logged a deferred 5-second penalty after one failure). IdentitiesOnly yes keeps each server to the key meant for it.
  • A private key that sat readable by others may already have been copied by another account on that machine. chmod 600 stops ssh refusing it but does not undo that; on a shared machine, replace the key.
  • ssh -v output contains your user name, host names and key file paths. Redact those before posting it; the SHA256: fingerprints identify a key without revealing it.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it