Permission denied (publickey): causes and fixes

SSH says Permission denied (publickey)? See in one command whether your key was never offered or was refused, then fix it: eleven causes, each with a check.

On this pageFirst, see what was offeredCauses on the client sideCauses on the server sideRead the server's logThrough a jump hostWhat Gatesys SSH shows insteadFAQ

Permission denied (publickey) is the most common SSH error and one of the least helpful. It means the server accepts only public keys and did not accept one from you. It does not say whether you sent the wrong key, sent no key at all, or sent the right key to the wrong account. One command tells those apart, and after that the list of causes is short.

First, see what was offered

ssh -v deploy@server 2>&1 | grep -E 'Offering|Server accepts|Authentications that can continue|identity file'

The output falls into one of three patterns.

No Offering public key line at all. Your client had no key to send. The cause is on your side: see the client side.

debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.

A key was offered and the server asked again. The server looked for that key in the account’s authorised keys and did not find it, or was not allowed to read them. See the server side.

debug1: Offering public key: /home/alice/.ssh/id_ed25519 ED25519 SHA256:Zq3...
debug1: Authentications that can continue: publickey

Server accepts key, and then it fails anyway. The key is authorised, and the signature step failed: a wrong passphrase, an agent that refused to sign, or a signature algorithm the two sides do not share.

Do this once and read it. Do not try key after key: every refusal counts towards the server’s MaxAuthTries, and fail2ban may ban your address after a few.

Causes on the client side

1. The wrong user name

The key is authorised for one account, and you asked for another. Cloud images have their own default users: ubuntu on Ubuntu, ec2-user on Amazon Linux, admin or debian on Debian, fedora on Fedora. root is often closed.

ssh ubuntu@server

2. The key is not where ssh looks

OpenSSH tries the agent’s keys, then default files such as ~/.ssh/id_ed25519 and ~/.ssh/id_rsa. A key with any other name has to be named:

ssh -i ~/.ssh/work_ed25519 deploy@server

Or for good, in ~/.ssh/config:

Host server
    User deploy
    IdentityFile ~/.ssh/work_ed25519
    IdentitiesOnly yes

3. The agent is empty

ssh-add -l

The agent has no identities means nothing is loaded. Load the key with ssh-add ~/.ssh/work_ed25519. On macOS, ssh-add --apple-use-keychain keeps the passphrase across restarts.

4. Too many keys

If the agent holds six keys, ssh offers them one after another, and the server hangs up after its limit, before the right one comes round. The message is then Too many authentication failures. IdentitiesOnly yes, as above, makes ssh offer only the key you named.

5. The private key file is too open

WARNING: UNPROTECTED PRIVATE KEY FILE!
Permissions 0644 for '/home/alice/.ssh/id_ed25519' are too open.

ssh refuses to use it. Fix the mode:

chmod 600 ~/.ssh/id_ed25519

6. An old RSA key against a new server, or the reverse

Since OpenSSH 8.8, RSA signatures with SHA-1 (the ssh-rsa algorithm) are off by default. Between a modern client and a very old server, or the other way round, the debug output shows:

debug1: send_pubkey_test: no mutual signature algorithm

The real fix is an Ed25519 key, or an upgrade of the old side. As a stopgap for one host:

Host old-router
    PubkeyAcceptedAlgorithms +ssh-rsa
    HostKeyAlgorithms +ssh-rsa

Causes on the server side

You need another way in for these: an existing session, a console, or a colleague.

7. The public key is not in authorized_keys

Compare fingerprints rather than eyeballing long strings. On your computer:

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

On the server, as the account you log in to:

ssh-keygen -lf ~/.ssh/authorized_keys

If your fingerprint is not in the second list, add the key with ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@server from a machine that can still log in, or paste the one-line public key into the file. A key that wrapped onto two lines when it was pasted does not count.

8. Wrong permissions on the server

With StrictModes on, which is the default, sshd ignores authorized_keys if anyone else could have written it. The server’s log says Authentication refused: bad ownership or modes.

chmod go-w ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R "$USER": ~/.ssh

9. sshd is configured to refuse you

Ask sshd what applies to this user, with every Include and Match block resolved:

sudo sshd -T -C user=deploy | grep -iE 'pubkeyauthentication|authorizedkeysfile|allowusers|allowgroups|denyusers|permitrootlogin'

Look for pubkeyauthentication no, an authorizedkeysfile that points somewhere other than .ssh/authorized_keys, an allowusers list without you on it, or permitrootlogin no when you log in as root.

10. SELinux labels

On Fedora, RHEL and their relatives, a .ssh folder that was copied or restored from a backup can carry the wrong label, and sshd is then not allowed to read it.

restorecon -Rv ~/.ssh

11. The account itself

A locked or expired account, a home directory that is not mounted until after login, or a from="..." option on the key that excludes the address you come from. The server’s log names each of these.

Read the server’s log

When you can get in another way, the log is the shortest path. It says exactly what the client is never told.

sudo journalctl -u ssh -n 30          # Debian, Ubuntu
sudo journalctl -u sshd -n 30         # Fedora, RHEL, Arch
sudo tail -n 30 /var/log/auth.log     # or /var/log/secure

Through a jump host

With ProxyJump, the message carries a prefix: alice@bastion: Permission denied (publickey) and deploy@db-primary: Permission denied (publickey) are different problems on different machines. Each hop uses its own user and key. See Debugging a failed ProxyJump chain.

What Gatesys SSH shows instead

Gatesys SSH keeps what the failed attempt left behind and prints a diagnosis in place of the bare error. Its Hop Doctor report, on the free plan, has:

  • A headline that names the cause, for example permission denied for deploy (server offers: publickey); key refused instead of All configured authentication methods failed.
  • What happened to each method: offered and refused, or skipped and why, such as no agent running, a missing key file, or a passphrase that was not given.
  • What it knows locally: the account and method of the host’s last successful login, the matching entry in ~/.ssh/config, and the keys your agent holds.
  • Fixes as a diff: another user, another key, or a different order of methods, with Apply & retry.

It never authenticates a second time to work this out, so a diagnosis costs you nothing against MaxAuthTries.

FAQ

What does “Permission denied (publickey)” mean?

The server allows only public-key logins, and no key your client offered was accepted for that account. The word in brackets is the list of methods the server would still accept.

How do I fix “Permission denied (publickey)” on AWS EC2?

Use the image’s default user (ec2-user for Amazon Linux, ubuntu for Ubuntu) and the key pair the instance was launched with: ssh -i key.pem ec2-user@address. The key file must be mode 600.

Why does SSH still ask for a password when I have a key?

The key was not accepted, and the server then offered password login. Run ssh -v to see whether the key was offered, and check authorized_keys and its permissions on the server.

What are the right permissions for ~/.ssh?

700 for the .ssh directory, 600 for private keys and authorized_keys, 644 for public keys, and a home directory that the group and others cannot write to.

What is “Too many authentication failures”?

Your client offered more keys than the server’s MaxAuthTries allows. Name one key with IdentityFile and set IdentitiesOnly yes.

Keep reading

All posts
Guides

SSH ProxyJump: a practical guide to jump hosts

Reach servers behind a bastion with ssh -J and ProxyJump: config examples, multi-hop chains, scp and rsync through a jump host, and bastion hardening.

5 min read

Guides

Debugging a failed ProxyJump chain, hop by hop

An SSH connection through a bastion can fail at five steps on every hop. How to read the error, find the hop that broke, and test from the hop in front of it.

6 min read

Your servers, understood.

Download Gatesys SSH free. Start Pro when you want Farabi — the first 3 months are on us.