Fixing "Permission denied (publickey)" - Verifying SSH Public Key Auth

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 -v to 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: -v prints 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 -i makes 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 .ssh and authorized_keys are correct. Loose permissions make StrictModes ignore 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 ssh shows 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/ownership
  • error: Could not open authorized keys → path or existence problem
  • Invalid 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 -T to 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 (if no, key auth is disabled)
  • authorizedkeysfile .ssh/authorized_keys is as expected (not changed to a custom path)

After changing the config, apply it.

$ sudo systemctl reload ssh

Is the Key Loaded in ssh-agent?

Conclusion: When authenticating via the agent, an unloaded key is never offered. Use ssh-add -l to 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 -v show Offering public key?
  • [ ] Is the private key 600 and ~/.ssh 700?
  • [ ] Does specifying the key with -i work?
  • [ ] Is the login username correct?
  • [ ] Is the public key in the server's authorized_keys?
  • [ ] Are the owner and permissions of ~, ~/.ssh, and authorized_keys correct (StrictModes)?
  • [ ] Does sshd -T show pubkeyauthentication yes?
  • [ ] Does journalctl -u ssh show a rejection reason?
  • [ ] When using an agent, is the key in ssh-add -l?

Next Reading