Fixing "Permission denied (publickey)" - Verifying SSH Public Key Auth
What Does "Permission denied (publickey)" Mean?
Conclusion: You reached the server, but public key authentication was rejected. It is not a network or password problem — only the key failed to authenticate.
This error means the TCP connection succeeded and your client is talking to the server's sshd. That is a different stage from Connection timed out or Connection refused. The server is saying: "I tried publickey authentication, but I could not verify a valid key."
user@server: Permission denied (publickey).
The word in parentheses is the list of authentication methods the server is currently allowing. (publickey,password) means either a key or a password works, but (publickey) alone means password auth is disabled — your only path in is a working key.
Prerequisites
- Client: Ubuntu / macOS (the concepts are the same)
- Server: Ubuntu (OpenSSH server)
- Server-side checks need an alternate login (console etc.) or
sudo
What Should You Check First?
Conclusion: Run
ssh -vto see whether a key is offered and at which step the server rejects it. That alone splits the cause into client-side vs server-side.
The cause is broadly one of two: the client is not offering the right key, or the server is not accepting the offered key. Splitting these two first is the key move, and the -v output gives you the evidence.
$ ssh -v user@server.example.com
Lines to watch:
debug1: Offering public key: /home/user/.ssh/id_ed25519 ED25519 SHA256:... debug1: Authentications that can continue: publickey debug1: No more authentication methods to try.
If Offering public key never appears → the client is not offering a key (client-side problem).
If Offering public key appears but is still rejected → the server is not accepting the key (server-side problem).
Why Is the Key Rejected? The Big Picture
Conclusion: Causes fall into three layers — client, server, and sshd configuration. Working top-down keeps you from getting lost.
| Layer | Common cause | Command to check |
|---|---|---|
| Client | No key specified / not in agent / wrong username | ssh -v / ssh-add -l |
| Server | Public key missing from authorized_keys / bad perms or owner |
ls -la ~/.ssh |
| sshd config | PubkeyAuthentication no / custom AuthorizedKeysFile path |
sudo sshd -T |
The rest of this article walks through these three layers in order.
How Do You Read the ssh -v Output?
Conclusion:
-vprints each key tried and the auth methods the server says can continue. The core skill is spotting where the conversation stops.
Here are the typical patterns.
No key offered at all:
debug1: Authentications that can continue: publickey debug1: No more authentication methods to try.
There is no Offering public key line. The client could not find a key to use.
Key offered but rejected:
debug1: Offering public key: /home/user/.ssh/id_rsa RSA SHA256:... debug1: Authentications that can continue: publickey
A key was offered but the server did not accept it. Suspect the server's authorized_keys or permissions.
-vv / -vvv add more detail, down to key exchange and algorithm negotiation. For auth triage, -v is usually enough.
Client Side: Are You Offering the Right Key?
Conclusion: Check the private key's existence, permissions, and how it is specified. If
-imakes it work, the problem is in your config or agent.
Check 1: Does the key file exist?
$ ls -la ~/.ssh
Confirm you have the pair: id_ed25519 (private) and id_ed25519.pub (public).
Check 2: Private key permissions
If the private key permissions are too open, ssh refuses to use it for safety and warns Permissions 0644 for ... are too open.
$ chmod 700 ~/.ssh $ chmod 600 ~/.ssh/id_ed25519
Check 3: Specify the key explicitly
With multiple keys or no ~/.ssh/config, the intended key may not be offered.
$ ssh -i ~/.ssh/id_ed25519 user@server.example.com
If that works, the key itself is fine. Make it permanent in ~/.ssh/config.
Host server
HostName server.example.com
User user
IdentityFile ~/.ssh/id_ed25519
Check 4: Is the username correct?
What matters is whose authorized_keys your public key is registered in. A correct key with the wrong login user is still rejected.
$ ssh -i ~/.ssh/id_ed25519 deploy@server.example.com
Server Side: Checking authorized_keys and Permissions
Conclusion: Verify the public key is in
authorized_keys, and that the owner and permissions of.sshandauthorized_keysare correct. Loose permissions makeStrictModesignore the key.
If you can reach the server through another path (console or an existing session), inspect the target user's ~/.ssh.
Check 1: Is the public key registered?
$ cat ~/.ssh/authorized_keys
Look for a line matching your client's id_ed25519.pub. If it is missing, add it. To install it in one step from the client:
$ ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server.example.com
Or append the public key manually:
$ cat ~/.ssh/id_ed25519.pub | ssh user@server 'cat >> ~/.ssh/authorized_keys'
Check 2: Ownership and permissions (StrictModes)
sshd defaults to StrictModes yes, so if the home or .ssh permissions are loose, or the owner is wrong, it rejects authentication even with a correct key. This is a very common trap.
$ chown -R user:user ~/.ssh $ chmod 700 ~/.ssh $ chmod 600 ~/.ssh/authorized_keys
Note that a home directory writable by group/other is also rejected.
$ chmod go-w ~
The reason appears in the server log. A line like Authentication refused: bad ownership or modes for directory /home/user/.ssh confirms permissions or ownership are the cause.
How Do You Confirm the Reason in Server Logs?
Conclusion:
journalctl -u sshshows the server's auth log with the specific rejection reason — key mismatch, permissions, or wrong user. It stops the guessing.
$ sudo journalctl -u ssh -n 100 --no-pager
Follow in real time:
$ sudo journalctl -u ssh -f
On some distributions it lands in /var/log/auth.log.
$ sudo tail -f /var/log/auth.log
Typical lines:
Authentication refused: bad ownership or modes for directory→ permissions/ownershiperror: Could not open authorized keys→ path or existence problemInvalid user xxx→ wrong username
When Should You Suspect sshd_config?
Conclusion: Public key auth may be disabled, or the key file path may differ from the default. Use
sshd -Tto see the effective values.
The effective server config is best read with sshd -T rather than the raw file (it prints the merged result of Match blocks and included files).
$ sudo sshd -T | grep -Ei 'pubkeyauth|authorizedkeysfile'
Things to confirm:
pubkeyauthentication yes(ifno, key auth is disabled)authorizedkeysfile .ssh/authorized_keysis as expected (not changed to a custom path)
After changing the config, apply it.
$ sudo systemctl reload ssh
Do not lock yourself out when editing SSH config. Keep one existing session open and test reconnecting in a separate terminal. Confirm a new connection succeeds after reload before closing the session.
Is the Key Loaded in ssh-agent?
Conclusion: When authenticating via the agent, an unloaded key is never offered. Use
ssh-add -lto list loaded keys.
When you are not using IdentitiesOnly, or going through a bastion (ProxyJump), the keys loaded into the agent are used.
$ ssh-add -l
The agent has no identities. means no key is loaded. Add one.
$ ssh-add ~/.ssh/id_ed25519
If you use agent forwarding (-A), it assumes the key is present in your local agent.
Checklist When It Still Fails
Conclusion: Go client → server → sshd config → logs, clearing offering, registration, permissions, and effective settings one by one. Most cases converge on permissions or a wrong username.
- [ ] Does
ssh -vshowOffering public key? - [ ] Is the private key
600and~/.ssh700? - [ ] Does specifying the key with
-iwork? - [ ] Is the login username correct?
- [ ] Is the public key in the server's
authorized_keys? - [ ] Are the owner and permissions of
~,~/.ssh, andauthorized_keyscorrect (StrictModes)? - [ ] Does
sshd -Tshowpubkeyauthentication yes? - [ ] Does
journalctl -u sshshow a rejection reason? - [ ] When using an agent, is the key in
ssh-add -l?