The SSH error Permission denied (publickey) means the network is fine and the server answered, but it accepted none of the keys your computer offered — and it won't take a password either. The cause is almost always one of nine specific things, and ssh -v tells you which one in under a minute. This guide reads the ssh -v output and the server log line by line, gives the fix for each cause with the exact commands, unpacks the sshd_config.d trap on Ubuntu 22.04, solves the GitHub version of the same error separately and, if you are locked out of your server, walks you back in through the web console step by step.
What does SSH Permission denied (publickey) actually mean?
The word in parentheses is the list of login methods the server still accepts. (publickey) on its own means password login is disabled on this server, and the only way in is a key listed in that user's authorized_keys file. (publickey,password) means both methods were open and both failed; on AlmaLinux and Rocky you will usually see (publickey,gssapi-keyex,gssapi-with-mic), which means the same thing. The good news is that this error happens after the connection has been made: the IP, the port, the firewall and the SSH service are all fine, and the problem is purely authentication. Errors that come before this stage are a different story:
| Message | At which stage | Meaning |
|---|---|---|
| Connection timed out | Before connecting | Packets don't reach the server: it is powered off, a firewall is blocking the port, or the IP is wrong |
| Connection refused | Before connecting | The server is reachable, but nothing is listening on that port |
| Host key verification failed | Key exchange | The server's fingerprint differs from the one you saved, usually after a reinstall |
| Permission denied (publickey) | Authentication | The server rejected your key, and password login is disabled as well |
The fixes for the first three errors are in the troubleshooting section of our complete guide to connecting to a server with SSH. This article deals only with the last row — an error that has come up again and again in our support tickets.
One-minute diagnosis: which key did ssh -v actually send?
Run your usual command with -v added. The output is long, but only the lines that start with Authentications, Offering, Will attempt, Trying, Server accepts and Load key matter:
ssh -v root@203.0.113.10
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Offering public key: /home/ali/.ssh/id_ed25519 ED25519 SHA256:q3k…
debug1: Authentications that can continue: publickey
debug1: Trying private key: /home/ali/.ssh/id_rsa
debug1: No more authentication methods to try.
root@203.0.113.10: Permission denied (publickey).
This is the most common case: the client offered the id_ed25519 key, and the server immediately answered "methods that can continue: publickey" again — in other words, it doesn't recognize that key. The lines that matter, and what each one tells you:
| Line in the ssh -v output | Meaning | Go to |
|---|---|---|
| Offering public key: … followed straight away by Authentications that can continue | The server did not accept this key for this user | Cause 1, 2, 8 or 9 |
| no such identity: …, or no Offering line at all | The key file is not at the path you gave | Cause 3 |
| Load key "…": bad permissions | The client itself skipped the key because its permissions are too open | Cause 7 |
| Load key "…": invalid format | The key file is in a format OpenSSH can't read, usually a PuTTY .ppk | Cause 6 |
| Server accepts key, then no mutual signature supported | The key is right, but the two sides can't agree on a signature algorithm | Cause 5 |
| Too many authentication failures | The client tried several other keys before the right one, and the server closed the connection | Cause 4 |
If you still have a way into the server — an open SSH session in another window, or the web console — look at the other side as well. The server never tells the user why it rejected a key, but it does write the reason to its own log:
# Ubuntu / Debian (the unit is "ssh")
journalctl -u ssh -n 30 --no-pager
# AlmaLinux / Rocky (the unit is "sshd")
journalctl -u sshd -n 30 --no-pager
The lines you are looking for: Authentication refused: bad ownership or modes for directory /root/.ssh (cause 2), User ali from 198.51.100.7 not allowed because not listed in AllowUsers or ROOT LOGIN REFUSED (cause 8), and a line containing not in PubkeyAcceptedAlgorithms (cause 5). If none of these appear and all you see is Connection closed by authenticating user root … [preauth], the server rejected the key in the simplest way possible: that key is not in this user's authorized_keys (cause 1).
9 causes of Permission denied (publickey) and how to fix each one
1. The public key is not in that user's authorized_keys
The server reads only the ~/.ssh/authorized_keys file of the user you are logging in as; a key registered for ali does nothing for root. Three mistakes are common: the key is in another user's file, the private key was pasted instead of the public key (.pub), or the key was broken in two while it was being copied. Each key must be exactly one line:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI…Q9x ali@laptop
To compare, list the fingerprint of your local key next to the keys registered on the server; one of the lines must show the same SHA256 value that ssh -v printed on the Offering line:
# on your computer
ssh-keygen -lf ~/.ssh/id_ed25519.pub
# on the server
ssh-keygen -lf /root/.ssh/authorized_keys
If you can still log in with a password or another key, the easiest way to register the key correctly is ssh-copy-id, which also creates the directory and sets the permissions for you; the Windows equivalent is in our SSH connection guide.
2. Permissions or ownership of .ssh and authorized_keys
By default (StrictModes yes), sshd ignores a file that other users can write to, and that covers more than the file itself: the .ssh directory, and even the user's home directory, must not be writable by the group or by others. An accidental chmod 777 on the home directory, or a file uploaded over SFTP as a different user, produces exactly this error. On the server:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R "$(id -un):$(id -gn)" ~/.ssh
chmod go-w ~ # the home directory itself must not be group/world-writable
ls -ld ~ ~/.ssh ~/.ssh/authorized_keys
Correct output starts with drwx------ for .ssh and -rw------- for the file, and the user owns both. Run these commands as the user who is going to log in; if you are fixing another user's files as root, write the full path of that user's home directory instead of ~.
3. The client can't find the right key
Left to itself, SSH only tries the default names under ~/.ssh: id_ed25519, id_ecdsa, id_rsa and a few others. A key with a different name, or in a different place, has to be named explicitly:
ssh -i ~/.ssh/srv1_key root@203.0.113.10
or set once and for all in ~/.ssh/config:
Host srv1
HostName 203.0.113.10
User root
IdentityFile ~/.ssh/srv1_key
IdentitiesOnly yes
Another common trap is running the command with sudo: sudo ssh or sudo git pull reads root's keys, not yours.
4. Too many authentication failures: too many keys in ssh-agent
If ssh-agent or your key manager holds ten keys, the client offers them one after another, and sshd closes the connection after six failed attempts (MaxAuthTries 6) — before the right key ever gets its turn. The IdentitiesOnly yes line in the config file above fixes exactly this: only the key you named is sent. For a one-off connection: ssh -o IdentitiesOnly=yes -i ~/.ssh/srv1_key root@203.0.113.10.
5. Old RSA keys and newer OpenSSH (Ubuntu 22.04 and later)
Since OpenSSH 8.8, RSA signatures that use the SHA-1 hash (ssh-rsa) are disabled by default, and Ubuntu 22.04 ships with OpenSSH 8.9. The RSA key itself is still valid, provided the client signs with rsa-sha2-256 or rsa-sha2-512 — and old clients don't know how: older versions of PuTTY and WinSCP, and old SSH libraries embedded in scripts and applications. On the server side the sign is a log line containing not in PubkeyAcceptedAlgorithms; on the side of a new client connecting to a very old server, it is no mutual signature supported.
The proper fix is a fresh Ed25519 key, which every current version understands:
ssh-keygen -t ed25519 -C "ali@laptop"
together with updating the old client or library. Re-enabling ssh-rsa on the server with PubkeyAcceptedAlgorithms +ssh-rsa is only a stopgap, and it brings back an algorithm that was retired because SHA-1 is weak.
6. Key format: PuTTY .ppk versus OpenSSH
PuTTY stores keys in its own format (.ppk), and OpenSSH — that is, ssh in PowerShell, Linux and macOS — can't read it and reports invalid format. The reverse is true too: PuTTY won't take an OpenSSH key directly. PuTTYgen converts between them: open the key with Load, and for OpenSSH export it from the Conversions → Export OpenSSH key menu; for PuTTY, Load the OpenSSH key and save it as a .ppk with Save private key. On Linux:
puttygen mykey.ppk -O private-openssh -o ~/.ssh/id_ed25519
7. Windows: WARNING: UNPROTECTED PRIVATE KEY FILE!
Like its Linux counterpart, OpenSSH on Windows ignores a private key that other users can read. It prints Permissions for '…\id_ed25519' are too open, then This private key will be ignored, and the end result is, once again, Permission denied (publickey). It usually happens after a key has been copied from a USB stick or another folder. chmod doesn't work on Windows; in PowerShell, remove the inherited permissions and grant read access to yourself only:
icacls "$env:USERPROFILE\.ssh\id_ed25519" /inheritance:r
icacls "$env:USERPROFILE\.ssh\id_ed25519" /grant:r "$($env:USERNAME):(R)"
8. sshd settings: PermitRootLogin, AllowUsers and the sshd_config.d trap
Sometimes the key is fine and the server itself forbids this user from logging in: PermitRootLogin no blocks root even with a key (the value prohibit-password only blocks root logins with a password), AllowUsers rejects every user not on its list, and PubkeyAuthentication no switches key authentication off entirely. The trap many guides never mention: on Ubuntu 22.04 and Debian, the first directive in /etc/ssh/sshd_config is this line:
Include /etc/ssh/sshd_config.d/*.conf
and according to the sshd_config documentation, for each setting the first value read wins. So a file like 50-cloud-init.conf — written automatically on cloud images, including servers built with cloud-init — overrides a line you added at the bottom of the main file. Instead of guessing, ask sshd for the effective settings it is actually running with:
sudo sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|pubkeyauthentication|authorizedkeysfile|allowusers|pubkeyacceptedalgorithms) '
grep -r . /etc/ssh/sshd_config.d/
After every change, validate the configuration before applying it, so a typo can't take the service down: sudo sshd -t && sudo systemctl reload ssh (on AlmaLinux and Rocky: reload sshd).
9. SELinux on AlmaLinux and Rocky
On RHEL-family distributions with SELinux enabled, an authorized_keys file that was moved in from somewhere else with mv carries the wrong security label, and sshd isn't allowed to read it — even though the ordinary permissions are perfectly correct. You'll find its trace in /var/log/audit/audit.log as avc: denied, and the fix is a single line:
restorecon -Rv ~/.ssh
Locked out of your server? Get back in through the web console, no SSH needed
When password login is disabled and the key doesn't work, there is no way in over the network. The panel's web console, however, connects to the server's virtual screen and depends neither on SSH nor even on the server's network. A console login is also a local login, which sshd settings don't affect, so the root password works there.
Iran cloud server
- In the panel, open the server's page. If you don't know the root password or have changed it, set a new one in the "Change / reset root password" section of that page; the server must be powered on.
- On the "Console" tab, press "Open console" and log in as root with that password. The password isn't shown as you type; if you get "Login incorrect", check that your keyboard layout is set to English and Caps Lock is off.
- Send the public key with the "📋 Paste text" button rather than typing it; one wrong character in a key dozens of characters long brings back the same error:
mkdir -p /root/.ssh && chmod 700 /root/.ssh
echo 'ssh-ed25519 AAAAC3Nza…Q9x ali@laptop' >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
sshd -t && systemctl reload ssh # AlmaLinux/Rocky: systemctl reload sshd
International server (outside Iran)
The console of an international server opens from that server's page too, but it has no paste button, and typing a long key by hand isn't practical. The simpler route is to allow password login temporarily, send the key from your own computer with ssh-copy-id, and then close password login again. The root password is shown on the server's page in the "Access (root)" card; if it doesn't work, the "New password" button generates a fresh one — that button's confirmation message tells you whether the server will restart or has to be powered off first. Then, in the console, as root:
# "00-" sorts first, and the first value read wins
printf 'PasswordAuthentication yes\nPermitRootLogin yes\n' > /etc/ssh/sshd_config.d/00-temp.conf
sshd -t && systemctl reload ssh
From your own computer, send the key and test key login in a new window:
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@203.0.113.10
ssh -i ~/.ssh/id_ed25519 root@203.0.113.10
Once the key works, delete the temporary file to restore the previous state:
rm /etc/ssh/sshd_config.d/00-temp.conf && sshd -t && systemctl reload ssh
This method works on Ubuntu and Debian, which read the sshd_config.d directory; on AlmaLinux 8, put the same two lines temporarily at the top of /etc/ssh/sshd_config and remove them afterwards.
git@github.com: Permission denied (publickey) on git pull and git push
The same error with the git@github.com prefix means GitHub doesn't recognize the key of the server you are running git pull or git push from. From a server in an Iranian datacenter, GitHub's SSH endpoint was reachable and, with no key registered, returned exactly this:
ssh -T git@github.com
git@github.com: Permission denied (publickey).
For a server that pulls a single repository, the cleanest option is a deploy key: create a key on the server and add the contents of its .pub file in that repository's settings, under Deploy keys. Deploy keys are read-only by default, which is exactly what you want on a production server. Once the key is added, the correct test response is:
ssh -T git@github.com
Hi ali/shop! You've successfully authenticated, but GitHub does not provide shell access.
A few points that explain most "it still doesn't work" cases:
- A deploy key is attached to just one repository; for several repositories, create several keys and, in ~/.ssh/config, define a Host alias with its own IdentityFile for each one.
- The repository URL must use the SSH form (git@github.com:ali/shop.git); an https:// URL never touches the key at all. Check it with git remote -v.
- Run the deploy script as the same user whose ~/.ssh holds the key; sudo git pull, or running it as www-data, reads a different key. For a complete git-based deployment, see our guide to deploying Laravel on a VPS.
- If a network blocks port 22, GitHub also offers SSH on port 443 under the hostname ssh.github.com; GitHub's official guide explains the setup.
How to avoid getting locked out of your server again
Most lockouts happen in the five minutes when someone switches off password login. These habits make those five minutes safe:
- Don't close your current session until you have tested key login in a new window; an open session isn't dropped when sshd reloads.
- Run sshd -t before every reload, and afterwards use sshd -T to confirm that the effective value is the one you wanted.
- Keep the root password somewhere safe: the key is for logging in over the network, the password is for a rainy day in the console.
- Use an Ed25519 key with a passphrase, and keep a secure backup of the private key; losing your laptop shouldn't mean losing your server.
- Disable password login and create a separate user in the right order, following our Linux server security checklist; the order is exactly what keeps you from being locked out.
Want a practice server where you can try these settings without worrying? Create an hourly cloud server, work with keys, passwords and the console, then delete it; you only pay for those hours.
Frequently asked questions
What does Permission denied (publickey) mean?
It means the connection to the server succeeded, but the SSH server accepted none of the keys your computer offered for that user, and because only publickey appears in the parentheses, password login is disabled on the server too. So the problem is not the network, a firewall or a powered-off server; it is purely authentication. Run ssh -v to see which key was sent, then check the server log for the reason it was rejected.
Why can't I connect after disabling password login?
Because the key you thought was working never worked, and until that moment you were logging in with your password. The most common reasons are a key registered for a different user, wrong permissions on the .ssh directory, and the client not sending the right key. Log in as root with the password through the panel's web console, add your public key to that user's authorized_keys, and set the permissions to 700 and 600. Next time, test key login in a new window before disabling passwords.
What are the correct permissions for .ssh and authorized_keys?
The .ssh directory must be 700 and the authorized_keys file 600, and the user must own both. The user's home directory must not be writable by the group or by others either, because with the default StrictModes setting sshd checks it too and ignores the key if anything is wrong. The commands are chmod 700 ~/.ssh and chmod 600 ~/.ssh/authorized_keys. On your own computer, the private key must not be readable by other users.
I have the root password, but SSH says Permission denied (publickey). How do I get in?
Use the web console. sshd settings only restrict logins over the network and have no effect on console logins, so you can log in as root with that password. On Iran servers, add your public key to authorized_keys with the console's Paste text button; on international servers, temporarily allow password login with a file in sshd_config.d, send the key with ssh-copy-id, then delete the file. If you have forgotten the root password, the server's page in the panel can set a new one.
How do I fix git@github.com: Permission denied (publickey)?
The error means GitHub doesn't recognize this server's key. Create an Ed25519 key on the server, add the contents of its .pub file under Deploy keys in the repository's settings, then test with ssh -T git@github.com until it returns the success message. Make sure the repository URL uses the SSH form and that git runs as the same user the key was created for; sudo git pull reads root's keys. Each deploy key is attached to only one repository.