Fixing “Permission denied (publickey)”
The eight causes of this error in the order worth checking — from the wrong username to file permissions to the RSA algorithm modern OpenSSH now refuses.
Troubleshooting · Bartłomiej Żabicki · updated 2026-07-27 · 10 min read
deploy@web1.example.com: Permission denied (publickey).
Nine words, no clue. The good news is that this error is much narrower than it looks: the network worked, DNS worked, the SSH handshake completed, and the server told you exactly one thing — it will only accept a public key, and none of the ones you offered were acceptable.
That leaves a short list of causes. Here they are in the order worth checking, which is roughly the order of how often they turn out to be the answer.
First: make the client tell you what it did
Do not guess. Run the connection again with -v:
ssh -v deploy@web1.example.com
Three lines in that output answer most of the question:
debug1: Will attempt key: /Users/bart/.ssh/id_ed25519 ED25519 SHA256:AbCd...
debug1: Offering public key: /Users/bart/.ssh/id_ed25519 ED25519 SHA256:AbCd...
debug1: Authentications that can continue: publickey
- No "Offering public key" line at all → the client never sent a key. The problem is on your machine: cause 1, 2 or 3 below.
- "Offering" appears, then it moves on → the server saw your key and rejected it. The problem is on the server: cause 4, 5, 6 or 7.
That single distinction cuts the search space in half before you touch anything.
1. The username is wrong
Easily the most common cause, and the most embarrassing. authorized_keys is per-user: a key in
/home/deploy/.ssh/authorized_keys does nothing for ssh root@host.
ssh -v deploy@web1.example.com # not your local username by default
If you set User in ~/.ssh/config, confirm it is actually applying:
ssh -G web1 | grep '^user '
2. The client is not offering the key you think
Without an IdentityFile, SSH tries a fixed list of default names (id_ed25519, id_ecdsa,
id_rsa…) plus everything in your agent. A key called ~/.ssh/prod_key is not on that list and
will never be tried.
Host web1
HostName web1.example.com
User deploy
IdentityFile ~/.ssh/prod_key
IdentitiesOnly yes
IdentitiesOnly yes matters more than it looks — see cause 3.
3. Too many keys, and the server hung up first
Servers default to MaxAuthTries 6. Every key your client offers counts as an attempt, and
the agent's keys are offered before the one you named. With seven keys loaded, the server
disconnects before your correct key is ever tried — and the message is, of course, Permission denied (publickey).
In -v output this looks like several "Offering public key" lines followed by an abrupt
disconnect.
ssh-add -l # how many keys is the agent holding?
ssh-add -D # clear them all, if you want to prove the point
Fix it properly with IdentitiesOnly yes on the host block, which limits SSH to the keys you
explicitly named. More on the agent in
ssh-agent explained.
4. File permissions on the server
OpenSSH refuses to read authorized_keys if the file, the .ssh directory, or the user's home
directory is writable by anyone but the owner — and it does so silently from the client's
point of view.
# on the server, as the target user
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 755 ~ # home must not be group/world-writable
chown -R deploy:deploy ~/.ssh
The giveaway is in the server's log:
sudo journalctl -u ssh -n 30 # or /var/log/auth.log
# Authentication refused: bad ownership or modes for directory /home/deploy/.ssh
If you can read the server's auth log, check it early — it often names the cause outright.
5. The key is not actually in authorized_keys
Or it is, but mangled. A public key must be one line. Copy-paste through a chat client or an editor with hard wrapping frequently inserts a newline, which silently invalidates it.
# on the server: how many lines, and do they start correctly?
wc -l ~/.ssh/authorized_keys
cut -c1-20 ~/.ssh/authorized_keys
# compare fingerprints — client side
ssh-keygen -lf ~/.ssh/id_ed25519.pub
# server side
ssh-keygen -lf ~/.ssh/authorized_keys
The second command prints a fingerprint per line. If yours is not among them, the key is not installed, whatever you think you pasted.
6. Your RSA key is fine; its signature algorithm is not
This one broke a lot of previously working setups. OpenSSH 8.8 (2021) disabled the ssh-rsa
signature scheme by default, because it uses SHA-1. Your RSA key is not the problem — the
signature algorithm negotiated with it is.
Symptom: an RSA key that worked for years stops working right after a server upgrade, and -v
shows your key offered and refused.
The right fix is a new key:
ssh-keygen -t ed25519 -C "laptop-2026"
The temporary fix, if you cannot change the key yet, is to re-enable the old algorithm — on the server:
# /etc/ssh/sshd_config
PubkeyAcceptedAlgorithms +ssh-rsa
HostkeyAlgorithms +ssh-rsa
Treat that as a note-to-self with an expiry date, not a solution. Background in SSH keys explained.
7. The server is not looking where you think
Two settings move the goalposts:
# /etc/ssh/sshd_config
AuthorizedKeysFile .ssh/authorized_keys # can be repointed elsewhere
PubkeyAuthentication yes # can be off entirely
AllowUsers bart deploy # anyone not listed is refused
AllowGroups sshusers # same, by group
A Match block can override any of these for specific users, addresses or groups, and its effects
are easy to forget:
Match User backup
PubkeyAuthentication no
Check what the server actually resolved:
sudo sshd -T | grep -Ei 'pubkeyauth|authorizedkeysfile|allowusers|allowgroups'
sshd -T prints the effective configuration the same way ssh -G does for the client. It is the
fastest way to end an argument about what the config says.
8. SELinux has relabelled the file
On RHEL, Fedora, Rocky and friends, a .ssh directory created by an unusual path — restored from
a backup, copied with the wrong tool, made by a provisioning script — can end up with the wrong
security context. Everything looks right, and it still fails.
ls -Z ~/.ssh/authorized_keys # want ssh_home_t
restorecon -R -v ~/.ssh
The order, condensed
ssh -v— is the key even being offered?- Right username?
- Right key, and is it named with
IdentityFile? - Too many keys hitting
MaxAuthTries? →IdentitiesOnly yes - Permissions on the server's
~,~/.ssh,authorized_keys - Key actually present and one line in
authorized_keys - RSA + OpenSSH 9 → generate Ed25519
sshd -TforAllowUsers,AuthorizedKeysFile,Matchblocksls -Zif the distro uses SELinux
Nine times out of ten you stop at step 2, 4 or 5.
Keeping it from recurring
Most of these are avoidable with one habit: a named IdentityFile plus IdentitiesOnly yes in
your SSH config for every host, so there is never ambiguity about
which key is being offered to whom. A client that stores each host's key explicitly — as
Moray does, with the key in the device Keychain — removes the whole category, because there
is no "which of my eleven keys did it try" question to answer.
Written by Bartłomiej Żabicki
iOS developer writing Swift since 2015, with a homelab he administers from an iPhone more often than he would like to admit. Moray is the SSH client he wanted to exist.
Frequently asked
- What does “Permission denied (publickey)” actually mean?
- The server refused every authentication method your client offered and would only accept a public key. It is almost never a network problem — the connection worked and the handshake completed. Either the server has no matching key on file, could not read the file it lives in, or rejected the key's signature algorithm.
- Why did my RSA key stop working after a server upgrade?
- OpenSSH 8.8 disabled the ssh-rsa signature scheme, which uses SHA-1, by default. The key itself is fine — the signature algorithm is not. Either re-enable it explicitly with PubkeyAcceptedAlgorithms, or better, generate an Ed25519 key.
- How do I see which key SSH is actually offering?
- Run ssh -v and read the “Offering public key” lines. They list each key in order, followed by the server's response. If your key never appears, the client is not loading it; if it appears and is refused, the problem is on the server.
try it yourself
Moray does all of this natively
A real terminal, dual-pane SFTP, tunnels and jump hosts on iPhone, iPad and Mac. Keys stay in the Keychain, hosts sync over your own iCloud, and there is no account to make.
Keep reading
- 8 min“Host Key Verification Failed” — What It MeansThe one SSH warning you should never click through — and the two-minute check that tells you which case you're in.
- 11 minSSH from an iPhone or iPad: The Complete GuideWhat iOS actually permits, how to get a usable keyboard, and why your session drops when you switch apps.
- 10 minSSH Keys Explained: Ed25519, RSA, and Where They Should LiveWhich algorithm to pick, how the two halves work, and the one place a private key should ever be stored.