Published 2026-10-22 · Updated 2026-10-22
SSH Permission Denied (publickey): Causes and Fixes
Short answer: "Permission denied (publickey)" means the server refused every public key your client offered, and public key was the only method it still allowed. The most common causes are logging in as the wrong user, offering the wrong key (or so many agent keys that the server hangs up first), a public key missing from that account's authorized_keys, and file permissions or ownership that make sshd ignore the file. Less often an sshd_config rule such as AllowUsers or PermitRootLogin, or a key algorithm the server refuses, is to blame. Read the client with ssh -v, then the server log, and the cause is usually visible.
In this article
What the error really tells you Step 1: read the client side with ssh -v Step 2: read the server side Wrong user, wrong key, too many keys The key file, permissions and ownership sshd_config rules that block key login Key types, signature algorithms and FIDO keys Decision flow: what to check, in order Prevention checklist and when to use the provider console Frequently asked questionsQuick win (10 minutes)
- Run
ssh -v -l username your-serverand look for the lines "Offering public key" and "Server accepts key". They tell you which side to investigate. - Print your key fingerprint with
ssh-keygen -lf ~/.ssh/id_ed25519.puband compare it with the fingerprints in the target account'sauthorized_keys. - On the server run
namei -l /home/username/.ssh/authorized_keysand check that nothing on the path is writable by group or others. - Read the last lines of the server log with
sudo journalctl -u ssh -n 50 --no-pager(the unit issshdon some distributions). - Keep one working session or the provider console open before you change anything, so a wrong fix cannot lock you out further.
What the error really tells you
The full client message is a line that starts with the user and host and ends with Permission denied (publickey). The words in brackets are not a reason. In the OpenSSH client source the message is built from the list of authentication methods the server said could still continue. So (publickey) means the server will only accept keys, and (publickey,password) means it would also have accepted a password. It never says which key was wrong or why.
That vagueness is intentional. The server source carries a comment explaining that an unknown user and a user whose key was refused must be handled in exactly the same way, otherwise the MaxAuthTries counter would become a way to discover valid usernames. The practical consequence: the client cannot tell you the cause, and the real answer lives in two places, the verbose client output and the server log.
Two things are easy to confuse with this error. A warning about "REMOTE HOST IDENTIFICATION HAS CHANGED" is a known_hosts problem that happens before any login is attempted. A timeout or "connection refused" is a network or firewall problem, not a key problem. This guide is only about the case where the connection works and authentication fails. If you are setting up keys for the first time, start with key-based authentication and the SSH hardening guide.
Step 1: read the client side with ssh -v
The ssh(1) manual says that multiple -v options increase verbosity and that the maximum is 3. Start with one -v, and go to -vvv only if the output does not explain it. Always pass the username explicitly with -l so you are sure which account you are testing.
ssh -v -l deploy -p 22 203.0.113.10
The wording below comes from the OpenSSH client source and is abbreviated; the exact set of lines varies by version. Read the output from top to bottom:
- "Reading configuration data" and "Applying options for ..." show which config files and
Hostblocks changed your settings. A forgottenUserorIdentityFileline in~/.ssh/configis a frequent surprise. - "identity file ... type N" lists keys ssh found. The type is reported as -1 when no public key could be loaded for that entry, which on its own is not an error.
- "Will attempt key: PATH TYPE FINGERPRINT explicit" is the list ssh plans to use. The word
explicitmarks a key named by-iorIdentityFile, andagentmarks a key that comes from ssh-agent. If your key is not listed at all, the client never tried it. - "Skipping ... key ... corresponding algorithm not in PubkeyAcceptedAlgorithms" or "... not supported by server" means the key was dropped before it was offered. This is the algorithm problem covered later.
- "Offering public key: ..." means the key was sent to the server as a test. If the next line is another "Authentications that can continue" and there is no "Server accepts key", the server did not accept that key for that user. Go to the server side.
- "Server accepts key: ..." means the server found the key for this user. If you are still refused, the failure is in the signature step: a passphrase or agent confirmation that failed, a FIDO key that was not touched, or a second method required by
AuthenticationMethods. - "Trying private key: PATH" appears for an entry that has no public key loaded, so ssh reads the private key itself, which may prompt for a passphrase.
- "No more authentication methods to try." is the last line before the error you started with.
When the key is right but the output shows no offer, check the private key file itself. The manual says ssh simply ignores a private key file that is accessible by others, so chmod 600 ~/.ssh/id_ed25519 on your own machine is part of the fix.
Step 2: read the server side
If the client offered the right key and the server did not accept it, the server log says why. sshd logs through syslog, the manual's default facility is AUTH, and the default LogLevel is INFO. Where the lines land depends on your distribution, so use the journal where you have one:
sudo journalctl -u ssh -n 50 --no-pager
sudo journalctl -u sshd -n 50 --no-pager
One of the two unit names will exist. Look for these lines. Their wording comes from the OpenSSH source:
Invalid user NAME from ADDRESS port N: the account does not exist on this server. Wrong username.Failed publickey for NAME from ADDRESS port N ssh2: a key was tried and refused. The words "invalid user" are added when the account does not exist.Authentication refused: bad ownership or modes for directory /home/NAME(or "for file ..."): StrictModes rejected the path. See the permissions section.User NAME from ADDRESS not allowed because not listed in AllowUsers: an allow-list blocked the account.ROOT LOGIN REFUSED FROM ADDRESS port N:PermitRootLoginblocked root.Could not open user 'NAME' authorized keys 'PATH': Permission denied: sshd tried to read the key file and the open failed. sshd logs this at the normal level for any failure except a missing file.User NAME not allowed because shell ... does not exist(or "is not executable", or "account is locked"): the account itself is unusable for logins.
Note the last gap: a missing authorized_keys file is only logged at debug level, so at the default level a missing file leaves no hint. That is why a debug run helps. The sshd(8) manual says -d runs the server in debug mode: it sends verbose output to standard error, does not put itself in the background, does not fork and processes only one connection. Repeating -d raises the level, with a maximum of 3. Start a throwaway instance on another port so your normal daemon is untouched:
sudo /usr/sbin/sshd -d -p 2222
# in a second terminal, on the server itself:
ssh -v -p 2222 -l deploy localhost
The sshd source refuses to start without an absolute path, so give the full path to the binary (/usr/sbin/sshd is common). The instance reads the normal /etc/ssh/sshd_config, handles your single test connection and exits. Testing from the server itself avoids opening port 2222 in a firewall. If it exits at once, its error message names the problem, for example a missing privilege separation directory. The sshd_config manual warns that logging at a DEBUG level violates the privacy of users, so use this briefly and do not leave debug logging switched on. You can also print the settings that apply to a specific connection:
sudo sshd -T -C user=deploy,addr=203.0.113.50,host=server | grep -iE '^(allowusers|allowgroups|denyusers|denygroups|permitrootlogin|pubkeyauthentication|passwordauthentication|authorizedkeysfile|strictmodes|maxauthtries|authenticationmethods) '
As the manual explains, -T prints the effective configuration and -C supplies connection parameters so Match blocks are applied. More on the directive file in the sshd_config entry.
Wrong user, wrong key, too many keys
Wrong username. This is the cheapest cause to rule out. The server log shows "Invalid user" when the account does not exist. Provider images often create a default account other than root, and the name differs between images, so check your provider's instructions and pass it with -l or a User line in ~/.ssh/config.
Wrong key. A key pair is only useful if the public half is in the target account's file. Compare fingerprints, because comments in key lines prove nothing:
ssh-keygen -lf ~/.ssh/id_ed25519.pub
ssh-keygen -y -f ~/.ssh/id_ed25519
sudo ssh-keygen -lf /home/deploy/.ssh/authorized_keys
The first command prints the fingerprint of the public key file. The second prints the public key derived from the private key (the manual describes -y as reading a private key file and printing the public key), in case the .pub file is lost or does not match; compare its key body with the line in authorized_keys. The third lists every key the account accepts. Match the fingerprint with the one in the "Offering public key" line. See ssh-keygen for the options.
Too many keys. If an agent holds many identities, ssh offers them one by one, and the server counts failures per connection. At the limit, sshd logs "maximum authentication attempts exceeded" and the client prints "Too many authentication failures", usually before your correct key has even been tried. The sshd_config(5) default MaxAuthTries is 6. The release notes for OpenSSH 10.6 (2026-10-06) added a separate allowance, with a default of 6, for the "would you accept this key" tests, so a server on 10.6 or later lets more keys be checked before it disconnects. Raising the limit is the wrong fix. Make the client offer only the intended key:
Host web1
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519_web1
IdentitiesOnly yes
The ssh_config(5) manual describes IdentitiesOnly as intended for situations where ssh-agent offers many identities, and it limits ssh to the files named in the configuration or on the command line. List what your agent holds with ssh-add -l, and remember that a forwarded agent adds its own keys (see ssh agent forwarding). To test without editing the config, run ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_web1 -l deploy 203.0.113.10. Print the final settings that ssh would use with ssh -G web1, which the manual describes as printing the configuration after evaluating Host and Match blocks. Remember that for most directives the first obtained value wins, while IdentityFile entries accumulate.
Locked out and not sure why?
We read your SSH configuration and logs without changing anything, and tell you exactly which setting blocks the login.
Get your free server check Talk to a security engineerThe key file, permissions and ownership
Right file, right account. By default sshd reads .ssh/authorized_keys and .ssh/authorized_keys2 inside the home directory of the account you log in as. A key added to root's file does not work for deploy. The authorized_keys format is one key per line (blank lines and lines that start with # are comments), and the sshd manual's file format section lists the fields as options, key type, base64 key and comment. A key pasted over two lines, or pasted into a file named slightly wrong, is simply not a key. When password login still works, ssh-copy-id appends the key to the right file for you.
Permissions. The sshd manual says that if the file, the ~/.ssh directory or the user's home directory are writable by other users, the file could be modified or replaced by unauthorized users, and sshd will not use it unless StrictModes is set to no. The StrictModes default is yes. The manual's recommended permissions are read and write for the user and nothing for others on the file, and read, write and execute for the user and nothing for others on the directory. In numbers that is 600 and 700. The OpenSSH source also shows what is checked: the file and each directory up to the home directory must be owned by the user (or root) and must not be writable by group or others. A group-writable home directory is therefore enough to break key login.
sudo chown -R deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
sudo chmod go-w /home/deploy
namei -l /home/deploy/.ssh/authorized_keys
The last command uses namei in long format, which shows the mode bits and the owner of every component of the path, so a bad directory stands out. Do not "fix" this by setting StrictModes no or by making everything world writable. That removes the safeguard against another local user planting a backdoor key. Correct the permissions instead. For the underlying rule, see the authorized_keys entry and the OpenSSH source for safe_path.
Home directories on odd setups. Encrypted or network home directories that are not mounted when sshd looks for the file produce the same "no key found" symptom. The "Could not open user" log line (above) and a debug run show it. Check that the home directory is actually available before the login.
sshd_config rules that block key login
If the key and files are right, the server configuration is next. Read the effective values with sshd -T (shown above) rather than the file, because the first obtained value for a keyword wins, and Include files and Match blocks can override what you edited.
- PubkeyAuthentication. The manual default is
yes. If any line, including one in an included file, sets it tono, keys are never accepted. - PasswordAuthentication off and no working key. The default is
yes, and hardened servers set it tono. Then "Permission denied (publickey)" is correct behavior: the key is the only way in. Fix the key. Do not switch passwords back on in a hurry, see PasswordAuthentication. - AuthorizedKeysFile. The manual default is
.ssh/authorized_keys .ssh/authorized_keys2, and it accepts the tokens%h(home directory) and%u(user). If a config points somewhere else, for example a central directory, the file in the home directory is never read. Check it withsudo sshd -T | grep -i authorizedkeysfile. - AllowUsers, DenyUsers, AllowGroups, DenyGroups. Per the manual, if
AllowUsersis specified, login is allowed only for names that match, and users matched byDenyUsersare not looked up inAllowUsersat all. The groups work the same way. The log line is "not allowed because not listed in AllowUsers". Background in AllowUsers. - PermitRootLogin. The manual default is
prohibit-password, which disables password and keyboard-interactive login for root but still allows keys. Withno, root is refused whatever credentials are presented. Withforced-commands-only, a key works only if its entry carries acommandoption. The deny line is "ROOT LOGIN REFUSED FROM". See PermitRootLogin, and note that root must also pass anyAllowUserslist. - AuthenticationMethods. The manual describes it as the methods that must all complete before access is granted. A value such as
publickey,passwordmeans a valid key alone is not enough. The SSH two-factor guide shows safe rollouts of this. - Locked account or bad shell. sshd logs "User NAME not allowed because ..." with the reason, as listed in the server section.
SELinux. On a system with SELinux in enforcing mode, an access denial can stop a process from reading a file even when the modes are correct. This guide does not name a specific label type for SSH files, because a primary source for it was not found. To check, search the audit log for recent denials, and if the records mention sshd and your key file, ask restorecon what it would change before letting it change anything:
sudo ausearch -m avc -ts recent
restorecon -Rvn ~/.ssh
restorecon -Rv ~/.ssh
Per the ausearch(8) manual, -m selects a record type and recent means ten minutes ago. Per restorecon(8), the tool corrects inconsistent labels, -R recurses, -v shows changes and -n only checks. Run the check as the account whose files you are inspecting. A denied open appears in the sshd log as the "Could not open user" line.
Key types, signature algorithms and FIDO keys
RSA and SHA-1. The OpenSSH 8.8 release notes say that release disabled RSA signatures using the SHA-1 hash by default, because SHA-1 is cryptographically broken. The notes also say there is no need to replace ssh-rsa keys: existing RSA keys automatically use the stronger SHA-2 signatures where possible, which OpenSSH has supported since 7.2. Trouble appears when one end is an old SSH implementation that only knows the SHA-1 form. The client then logs a "Skipping" line, or the server refuses, and you see the usual denial. The release notes offer a stopgap for a single old host in ~/.ssh/config, and recommend moving legacy systems to ECDSA or Ed25519 keys:
Host old-host
HostkeyAlgorithms +ssh-rsa
PubkeyAcceptedAlgorithms +ssh-rsa
The ssh_config(5) manual explains that a leading + appends to the default list, - removes and ^ moves to the front, and that ssh -Q PubkeyAcceptedAlgorithms lists what your client supports. On the server, sudo sshd -T | grep -i pubkeyacceptedalgorithms shows what it accepts. Prefer generating a fresh Ed25519 key (ssh-keygen -t ed25519) over keeping SHA-1 alive.
Short RSA keys. OpenSSH 9.1 added RequiredRSASize, a minimum RSA key length. The sshd_config manual gives the default as 1024 bits, and keys below the limit are ignored for user authentication. A very old, short RSA key can therefore stop working after an upgrade with no obvious message.
FIDO (sk) keys. OpenSSH 8.2 added the ecdsa-sk and ed25519-sk key types for FIDO/U2F hardware tokens, through libfido2. These keys need the physical token. If it is unplugged, or you did not touch it when it blinked, or you skipped the PIN that -O verify-required demands, login fails. The server source logs "user presence (authenticator touch) requirement not met" when the touch is missing. A server can also require touch or verification for all keys with PubkeyAuthOptions. The 8.2 notes warn that hardware support for Ed25519 tokens is less common than for the ECDSA type. If a laptop was replaced and the key file is gone, the ssh-keygen manual says -K downloads resident keys from an authenticator into the current directory, but only for keys created with the resident option. Both ends also need OpenSSH 8.2 or later, so check ssh -V. More in the SSH two-factor authentication guide.
Decision flow: what to check, in order
- Run
ssh -v -l username your-serverand read the last twenty lines. Confirm the username is the account you expect. - Is your key listed under "Will attempt key" and then "Offering public key"? If not, fix the client: the
IdentityFilepath, the private key mode (chmod 600),ssh-add -l, or a "Skipping ... algorithm" line. - Do you see "Too many authentication failures"? Add
IdentitiesOnly yesand a singleIdentityFilefor that host. - Do you see "Server accepts key" and still fail? Look at the signature step: passphrase, agent confirmation, FIDO touch or PIN, or a second method in
AuthenticationMethods. - Was the key offered but never accepted? Read the server log for the lines listed in step 2: Invalid user, Authentication refused, not allowed, ROOT LOGIN REFUSED, Could not open.
- No telling log line? Compare the key fingerprint with the target account's
authorized_keys, and checkAuthorizedKeysFilewithsshd -T. - Check the modes with
namei -l: home directory,.sshand the file, owned by the user and not writable by group or others. - Compare the effective configuration with
sshd -T -Cfor this user and address. - Still unclear? Start the throwaway debug daemon on port 2222 and read its output while you connect once.
- If you cannot get in at all and have no other session, stop and use the provider console.
Prevention checklist and when to use the provider console
Most of these failures are self-inflicted during a configuration change, so the checklist is about making changes safe:
- Keep a second SSH session open while you change
sshd_config, runsudo sshd -tbefore reloading, and test a brand-new login before closing the old one. - Create
.ssh(700) andauthorized_keys(600) with correct ownership when you provision an account, and never leave the home directory writable by group or others. - Use one key per person and device, with a descriptive comment, and record fingerprints so you can audit them later.
- Put an
IdentityFileandIdentitiesOnly yesin~/.ssh/configfor each host instead of relying on whatever the agent holds. - Add the account to
AllowUsersorAllowGroupsbefore you enable the list, and include automation accounts. - Turn off
PasswordAuthenticationonly after key login has been proven from a fresh session. - Keep a spare administrator key or a second FIDO token stored somewhere safe, and know your provider's console login before you need it.
- Watch the log: repeated failures from your own address can also trigger a ban, see SSH brute-force protection.
When to stop and use the provider console. Stop guessing at the SSH login when you have lost your only working key, when a configuration change closed your last session, or when the server log cannot be read because you cannot log in. Every extra failed attempt is another log line, and repeated attempts can get your address blocked. A web console or rescue mode logs in locally, and the PermitRootLogin and AllowUsers rules for SSH do not apply to it. From there you can read the log, fix authorized_keys or sshd_config, run sshd -t and reload. The SSH locked out recovery guide walks through that safely.
One more reason to be careful: if authorized_keys contains a key nobody can explain, or the file changed when nobody edited it, do not simply delete it. Treat it as possible compromise and follow the server breach response guide first.
Frequently asked questions
What does Permission denied (publickey) mean?
It means the SSH server refused every public key your client offered and public key login was the only method still allowed. The text in brackets lists the methods the server said could continue. It does not give the reason, which you find with ssh -v on the client and the log on the server.
Why does SSH say too many authentication failures?
The server counts failed attempts per connection and disconnects at MaxAuthTries, which defaults to 6. If your ssh-agent holds many keys, the client offers them one after another and can hit the limit before the right key is tried. Name one key with IdentityFile and set IdentitiesOnly yes for that host.
How do I fix Permission denied (publickey) when my key is in authorized_keys?
Check the server log. Usual causes are a file or directory writable by group or others (StrictModes), a key in the wrong account, a different AuthorizedKeysFile path, or an AllowUsers or PermitRootLogin rule. Compare fingerprints with ssh-keygen -lf and check modes with namei -l.
What permissions does authorized_keys need for SSH to accept it?
The sshd manual recommends read and write for the user and nothing for others on the file, and the same plus execute on the .ssh directory, which is 600 and 700. With StrictModes on, the file, the .ssh directory and the home directory must not be writable by group or others and must be owned by the user or root.
Why does SSH key login work for root but not for my other user?
The two accounts use different files and different rules. Root has its own authorized_keys, and PermitRootLogin defaults to prohibit-password, which still allows keys. Another user needs the key in its own home directory, correct modes, and a place in any AllowUsers or AllowGroups list.
Why did SSH key login stop working after an OpenSSH upgrade?
OpenSSH 8.8 disabled RSA signatures that use SHA-1 by default. Most RSA keys keep working through SHA-2, but an old client or server that only supports SHA-1 will be refused. Use an Ed25519 key, or re-enable ssh-rsa for that single host with PubkeyAcceptedAlgorithms as a stopgap.
How can I see why sshd rejected my key?
Read the server log with journalctl for the ssh or sshd unit, and look for lines such as Invalid user, Authentication refused, not allowed because or Could not open user. For more detail, run a temporary daemon with sudo /usr/sbin/sshd -d -p 2222 and connect to port 2222 once.
Should I turn on PasswordAuthentication to get back in?
Only as a short, deliberate step from the provider console, and switch it off again after the key works. Turning it on over a live internet connection reopens the guessing attack you disabled. Fixing the key or the permissions is the lasting answer.
Not sure where your server stands?
Get a free, read-only security check, or talk to a security engineer about managed protection.
Get your free server check Talk to a security engineer