Skip to content
AnyStorage
Free Download

SFTP & SSH Keys

SFTP Permission Denied (publickey): The Fix List

The parenthesis in Permission denied (publickey) lists what the server still allows, not what failed. How to read ssh -v, and the seven causes behind the message.

What OpenSSH actually means by Permission denied (publickey), the file permissions and key formats the server insists on, and the algorithm change that broke old RSA keys.

sftp permission denied publickey, permission denied publickey sftp, authorized_keys permissions

The line, and the detail everyone misreads

sh

$ sftp alice@files.example.com
alice@files.example.com: Permission denied (publickey).

That message is generated in one place in OpenSSH's client, and its format string is worth seeing:

text

fatal("%s@%s: Permission denied (%s).",
    authctxt->server_user, authctxt->host, authlist);

The last field is authlist — the list of authentication methods the server is still willing to accept, not the one that failed. So Permission denied (publickey) means: I tried everything I had, the server only offers public-key authentication, and my key was not accepted. If it said (publickey,password) you would have a password fallback; because it does not, there is no point looking for one.

Symptom, cause and fix
What you seeCauseFix
Fails instantly, -v shows no "Offering public key"Client never found or offered the key-i, IdentitiesOnly yes
-v offers the key, server still refusesKey not in authorized_keys, or wrong userCheck the file for that exact account
Works for one user, not anotherPermissions on ~, ~/.ssh, authorized_keys700 on the directory, 600 on the file
-v shows "no mutual signature algorithm"ssh-rsa disabled since OpenSSH 8.8New key type, or re-enable per host
Server log says "invalid format"Wrong key file: .ppk, or a public key as privateConvert to OpenSSH format
Only administrator accounts fail on Windowsadministrators_authorized_keys not usedWrite that file, fix its ACL
Fails only in a script or on a jump hostNo agent, or agent not forwardedssh-add, ForwardAgent deliberately

1. Read the verbose log first

Everything below is guesswork until you have seen the client's own account of the handshake.

sh

ssh -v alice@files.example.com
sftp -v alice@files.example.com

Three lines carry the answer, and all three are literal strings in OpenSSH's source. Authentications that can continue: publickey is the server's method list. Offering public key: /Users/alice/.ssh/id_ed25519 means the client actually sent that key — if no such line appears, the problem is entirely client-side. And no mutual signature algorithm is the algorithm mismatch covered in step 4.

On the server, raise the log level in sshd_config: LogLevel accepts QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, DEBUG3, with INFO as the default. VERBOSE is enough to log key fingerprints; the manual warns that logging at DEBUG level "violates the privacy of users and is not recommended".

2. Fix the permissions, both ends

This is the most common server-side cause and the least visible, because a correct key in a world-writable directory is silently ignored. The sshd manual is explicit: for ~/.ssh "the recommended permissions are read/write/execute for the user, and not accessible by others", and for ~/.ssh/authorized_keys "the recommended permissions are read/write for the user, and not accessible by others". The reason follows: "If this file, the ~/.ssh directory, or the user's home directory are writable by other users, then the file could be modified or replaced by unauthorized users", and in that case "sshd will not allow it to be used unless the StrictModes option has been set to 'no'". StrictModes defaults to yes.

sh

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod go-w ~
ls -ld ~ ~/.ssh ~/.ssh/authorized_keys

Do the same on the client: a private key readable by others is refused by ssh itself, chmod 600 ~/.ssh/id_ed25519.

3. Check the file, the format and the username

authorized_keys is one key per line, and the manual describes the fields as "options, keytype, base64-encoded key, comment", with the options field optional. Line breaks inserted by a copy-paste — or by a browser downloading the key — split the base64 blob and silently invalidate the entry.

sh

ssh-keygen -lf ~/.ssh/id_ed25519.pub
tail -c 100 ~/.ssh/authorized_keys | cat -A | tail -2

Two more things in this family. The key must be in the authorized_keys of the account you are logging in as, which is why sftp root@host fails with a key installed for alice. And AuthorizedKeysFile in sshd_config can point somewhere else entirely — it "may include wildcards" and tokens, so a hardened host may read /etc/ssh/keys/%u instead of the home directory.

4. The algorithm change that broke old RSA keys

If your key worked for years and stopped, this is why. The OpenSSH 8.8 release notes state: "This release disables RSA signatures using the SHA-1 hash algorithm by default. This change has been made as the SHA-1 hash algorithm is cryptographically broken." That removes the ssh-rsa signature algorithm — not RSA keys as such, but the SHA-1 signature made with them.

The current default list in ssh_config for PubkeyAcceptedAlgorithms contains rsa-sha2-512 and rsa-sha2-256 and no ssh-rsa. Ask your own client what it will do:

sh

ssh -Q PubkeyAcceptedAlgorithms

The documented stopgap, straight from the release notes, re-enables it for one destination — the notes describe it as "only as a stopgap measure until legacy implementations can be upgraded or reconfigured with another key type (such as ECDSA or Ed25519)":

text

Host old-host
    HostkeyAlgorithms +ssh-rsa
    PubkeyAcceptedAlgorithms +ssh-rsa

The + prefix appends to the default set rather than replacing it; - removes, and ^ puts entries at the head. The better fix is a new key: ssh-keygen -t ed25519.

5. Agent, passphrase and the too-many-keys problem

If the private key is encrypted and nothing prompts you — a cron job, a CI runner, a GUI app — the client has no way to unlock it. Load it into the agent once:

sh

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l

The opposite failure exists too. A server with MaxAuthTries at its default of 6 will cut you off before the client reaches the right key if the agent offers a dozen. IdentitiesOnly is the fix: it tells ssh to "only use the configured authentication identity and certificate files … even if ssh-agent or a PKCS11Provider or SecurityKeyProvider offers more identities".

sh

ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 alice@files.example.com

For jump hosts, prefer ProxyJump over forwarding your agent. If you do forward it, do it per host, never globally.

6. Windows servers have a second key file

This one wastes whole afternoons because the standard advice is wrong on Windows for exactly the accounts you test with. Microsoft's documentation is clear: for an administrative user, the public key goes into a file called administrators_authorized_keys in C:\ProgramData\ssh\, and "This file only applies to administrator accounts. You must use it instead of the user-specific file within the user's profile location." The ACL must allow only administrators and SYSTEM:

powershell

icacls.exe "$env:ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"

Also note, from the same page, that Windows OpenSSH does not support the AuthorizedKeysCommand and AuthorizedKeysCommandUser directives, and that key-based authentication works with local and Active Directory accounts but not Microsoft Entra ID accounts.

Connecting once the key works

With authentication fixed, the remaining question is what you do with the connection. AnyStorage (v0.2.24; macOS 11+, Windows 10+, Ubuntu 20.04+) connects to SFTP hosts with key authentication alongside S3-compatible endpoints and WebDAV, in one window, and the free tier allows two connections. When you want the host as a drive rather than a file list, it mounts through a built-in local WebDAV server at http://127.0.0.1:3211 — no FUSE, no WinFsp, no macFUSE, which also means no sshfs to debug on top of the key problem you just solved.

Does (publickey) mean my key is wrong?

It means the server will only accept public-key authentication and nothing you offered satisfied it. That includes "you offered nothing", which is why ssh -v and the "Offering public key" line are the first check.

Why does ssh work but sftp fail?

Same authentication, different service. If keys work for ssh and sftp fails later, look at the Subsystem line in sshd_configsftp-server or internal-sftp — and at ChrootDirectory, whose ownership sshd checks unconditionally.

Can I still use my old RSA key?

Yes, if it is a genuine RSA key of adequate length: the modern rsa-sha2-256 and rsa-sha2-512 signature algorithms use the same key. Only the SHA-1 ssh-rsa signature is disabled by default.

Is a .ppk file usable?

Not directly. PuTTY's format is its own; export the key with PuTTYgen's Conversions menu to an OpenSSH private key, or generate a new pair with ssh-keygen.

Next steps