How to Fix "Permission denied (publickey)" in SSH
Permission denied (publickey). is the server telling you two things: it only accepts key-based logins, and none of the keys your client offered were accepted. The cause is almost always one of a handful of things — and ssh -v will tell you which.
Step 1: watch the handshake
ssh -v user@host
The lines that matter:
debug1: Authentications that can continue: publickey
debug1: Offering public key: /home/you/.ssh/id_ed25519 ED25519 SHA256:…
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
You now know which keys were offered and that the server refused each one. If the key you expected isn't in the list, the problem is on your side; if it was offered and refused, it's on the server's.
Wrong username
Each cloud image has its own default user: ubuntu on Ubuntu, ec2-user on Amazon Linux, admin on Debian AMIs, and often root elsewhere. For GitHub and GitLab, the user is always git:
ssh -T git@github.com
# Hi your-name! You've successfully authenticated, but GitHub does not provide shell access.
The right key isn't being offered
Point ssh at the key explicitly:
ssh -i ~/.ssh/my-server-key user@host
To make that permanent, add a block to ~/.ssh/config:
Host myserver
HostName 203.0.113.10
User ubuntu
IdentityFile ~/.ssh/my-server-key
IdentitiesOnly yes
IdentitiesOnly yes stops ssh offering every key in your agent first. Servers give up after a few failed attempts, so an agent holding many keys can trigger Too many authentication failures before the right one is tried.
Your public key isn't on the server
The server checks ~/.ssh/authorized_keys for the user you log in as. Add your public key with:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
If you can't log in at all, add it through your cloud provider's console or a recovery shell.
Permissions on the server are too open
With its default StrictModes, sshd ignores authorized_keys if the files are writable by others. The server's auth log says so explicitly — Authentication refused: bad ownership or modes in /var/log/auth.log (or journalctl -u ssh). Fix the modes:
chmod go-w ~ # home directory: not writable by group or others
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Permissions on your private key are too open
The client has its own check. If your private key is readable by other users, ssh refuses to use it:
WARNING: UNPROTECTED PRIVATE KEY FILE!
Permissions 0644 for '/home/you/.ssh/id_ed25519' are too open.
chmod 600 ~/.ssh/id_ed25519 # or 400, read-only
Public keys (.pub) can stay at 644; only the private half must be private. AWS's .pem keys need the same treatment — that's why its guides say chmod 400.
The agent doesn't have your key
If you rely on ssh-agent, check what it holds:
ssh-add -l
ssh-add ~/.ssh/id_ed25519
On macOS, ssh-add --apple-use-keychain ~/.ssh/id_ed25519 stores the passphrase in the Keychain so it survives reboots.
Old RSA keys and old servers
OpenSSH 8.8 (2021) disabled RSA signatures using SHA-1 (ssh-rsa) by default. A modern client connecting to an old server that only supports ssh-rsa, or an old client meeting a hardened server, can end in Permission denied with an RSA key that worked for years. The clean fix is a modern key:
ssh-keygen -t ed25519 -C "you@example.com"
Then add the new public key to the server or to GitHub.
Quick checklist
ssh -v— which keys are offered?- Right user for this server?
- Right key —
-iorIdentityFile, withIdentitiesOnly yes? - Public key in the server's
authorized_keys? - Server: home not group-writable,
~/.ssh700,authorized_keys600. - Client: private key 600 or 400.
- Still stuck with an old RSA key? Generate an ed25519 key.
For any other permission combination, the chmod calculator shows exactly who can do what.