SSH Permission denied (publickey) (tested)

Permission denied (publickey) means the server rejected every key your client offered, including offering none at all. OpenSSH gives the same short message for a dozen different root causes on purpose, for security: it never tells an attacker which part was wrong. We built a throwaway sshd, read its own debug log, and matched each server-side cause to what the client actually shows.

1. What the message means

The client tried every key it had (or had none to try) and the server said no to all of them. That is all Permission denied (publickey) tells you. The text in parentheses lists the authentication methods the server still allows, not what you did wrong. We measured the server side with its own debug log to find the real cause behind seven cases that all look identical to the client.

2. Test setup

We ran a throwaway sshd on 127.0.0.1:8983 with a fresh ed25519 host key, PubkeyAuthentication yes, and a dedicated AuthorizedKeysFile, started as a normal user (no root, no real account). The server ran with LogLevel DEBUG3 so we could read its real reason for every rejection, separate from what the client saw.

$ ssh-keygen -t ed25519 -f hostkey -N ""
$ /usr/sbin/sshd -D -e -f sshd_config -p 8983
$ ssh -p 8983 -i clientkey jacque@localhost

3. No key offered at all

With no identity available, the client never sends a public key, and the server rejects immediately:

jacque@localhost: Permission denied (publickey).

Run with -v and the picture is clearer. You see the server's allowed method list before the client even tries anything:

debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
jacque@localhost: Permission denied (publickey).

4. Same client error, two different server causes

We measured two completely different problems that produce the identical client-side message and exit code 255:

CauseClient seesServer's own log says
Key is valid but simply not in authorized_keysPermission denied (publickey).Failed publickey for jacque ... ED25519 SHA256:... / key is not allowed
authorized_keys sits under a world-writable directory (ours was forced under /tmp, mode 1777)Permission denied (publickey).Authentication refused: bad ownership or modes for directory /tmp / Ignored authorized keys: bad ownership or modes for directory /tmp

The client cannot tell these apart. Only the server's own log names the real cause, and only if you can read it.

5. The sticky bit does not save you

We expected /tmp's sticky bit (mode 1777) to be special-cased, since it stops other users deleting your files. It is not exempt from OpenSSH's StrictModes check. Any authorized_keys path with a world-writable ancestor directory anywhere above it, sticky bit or not, gets silently rejected the same way: the correct key, with correct 600 permissions on the file itself, still fails, and the server log blames the directory by name, not the file.

6. The "644 breaks SSH" claim, checked

A common claim is that chmod 644 authorized_keys breaks login. We measured it directly, with StrictModes no so the (unrelated) /tmp directory problem from section 5 could not interfere: 644 logged in fine, and so did 666 (world-writable). With StrictModes no, OpenSSH skips file and directory permission checks entirely, by design, for setups like NIS-mounted home directories.

With StrictModes yes (the default) and everything else clean, OpenSSH's own source checks for group/world-writable permissions, not merely world-readable ones. 644 (rw-r--r--) is not group/world-writable, so per the code path it should pass; 666 or 777 would not. We could not isolate that single file-level check in our own rig, because every path we are allowed to use lives under /tmp, and section 5's directory-level rejection fires first and masks it, every time, at any file permission. That is itself the finding: under StrictModes yes, a bad ancestor directory and a bad file both produce the exact same client message, and the directory check wins the race, so you cannot tell which one is broken without testing them one at a time, as we did here.

7. AuthorizedKeysFile pointing nowhere

We pointed AuthorizedKeysFile at a path that does not exist. sshd did not log a missing-file warning anywhere, even at DEBUG3. It silently behaved as if the key list were empty:

debug3: mm_answer_keyallowed: publickey authentication test: ED25519 key is not allowed
Failed publickey for jacque ... ssh2: ED25519 SHA256:...

The correct key, offered correctly, with a typo'd config path: same "not allowed" line as a key that was never generated. No hint that the path itself is the problem.

8. The method list in the error changes with sshd_config

The text inside the parentheses is not fixed. It lists whichever methods the server still has open, which depends on sshd_config, not on you:

Server configClient error
PasswordAuthentication no, KbdInteractiveAuthentication noPermission denied (publickey).
PasswordAuthentication yesPermission denied (publickey,password).
KbdInteractiveAuthentication yesPermission denied (publickey,keyboard-interactive).

Seeing password or keyboard-interactive in the message means the server would have let you type a password or answer a prompt; it does not mean your key setup is any more or less broken. gssapi-with-mic can appear the same way if GSSAPIAuthentication yes is set; we did not test a working Kerberos setup, so that part is per the OpenSSH docs, not measured.

9. Use -v: it is the actual fix for diagnosing this

Default ssh output hides almost everything useful. ssh -v shows which identity files it tried and which key it actually sent:

debug1: identity file /tmp/sshtest/otherkey type 3
debug1: Will attempt key: /tmp/sshtest/otherkey ED25519 SHA256:ecA2... explicit
debug1: Offering public key: /tmp/sshtest/otherkey ED25519 SHA256:ecA2... explicit
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
jacque@localhost: Permission denied (publickey).

Compare the fingerprint sshd logged against what you expect with ssh-keygen -lf your_key.pub. If "Offering public key" never appears, no key was sent at all (section 3), which is a different problem from a key that was sent and refused (section 4). -vv or -vvv adds more, but plain -v already answers most cases.

10. Checklist, in the order we'd check it

Frequently asked questions

Why does SSH say Permission denied (publickey) instead of a specific reason?

By design. OpenSSH never tells a client which part of authentication failed, so an attacker can't learn anything from the error. We measured this directly: a missing key, a key not in authorized_keys, a world-writable directory, and a wrong AuthorizedKeysFile path all produced the exact same client-side text and exit code 255.

Does chmod 644 on authorized_keys really break SSH login?

We measured it: no, 644 alone logged in fine, and even 666 worked once we removed an unrelated directory problem (StrictModes no). The real rule, per OpenSSH's own checks, is group/world-WRITABLE permissions, not merely world-readable ones. 644 is readable, not writable, by group/other.

Why did my key fail even though the file permissions looked right?

Check every directory above authorized_keys, not just the file. We measured a case where the file itself was 600 (correct) but a parent directory was world-writable, and sshd rejected the login anyway, logging 'bad ownership or modes for directory' server-side while the client just saw the generic Permission denied message.

What does (publickey,password) in the error mean vs just (publickey)?

It lists the authentication methods the server still has enabled, taken from sshd_config, not a hint about your key. We measured the exact same wrong key against three server configs and got three different parenthesized lists: (publickey), (publickey,password), and (publickey,keyboard-interactive), by toggling PasswordAuthentication and KbdInteractiveAuthentication.

What's the single most useful command to debug this?

ssh -v. Default output hides which identity files were tried and which key, if any, was actually sent to the server. In our tests, -v showed lines like 'Offering public key: ... explicit' when a key was sent, and that line was simply absent when no usable key existed, which is the fastest way to tell those two situations apart.

Written with AI assistance. Measured on 2026-10-02 with OpenSSH_10.0p2 (Debian 13), both client and server, against a throwaway sshd on 127.0.0.1:8983 with a fresh ed25519 host key and a dedicated AuthorizedKeysFile (no real accounts involved). Server-side causes were confirmed by running sshd with LogLevel DEBUG3 and reading its own log, not guessed from the client error. PlainHeaders is our extension; OpenSSH (ssh, sshd, ssh-keygen) is free.