Troubleshooting tutorial, 2026
“Permission denied (publickey)”? Let the server tell you why.
Most fixes for this error are guesses in a list. We broke a real server twelve different ways and wrote down exactly what each one looks like, on both ends.
What you see, every time
Permission denied (publickey).What the server knows
Invalid user deploybad ownership or modes for directory ~/.sshbad ownership or modes for file authorized_keysnot listed in AllowUsersmaximum authentication attempts exceededno mutual signature algorithm
The short answer
The server refused every key you offered, and that message is the same for every cause. The reason is written in the server’s log: run sudo journalctl -u ssh -n 50 on the server (through the web console if you’re locked out; every LiteKeep server has one).
The usual culprits: the wrong user name, your key missing from ~/.ssh/authorized_keys, permissions on ~/.ssh (use 700) or the file (600), too many keys offered, or a file saved in the wrong format on Windows. Paste your error into our free decoder below.
Here’s why this error is so maddening.
We set up a test server and caused twelve different login failures: a wrong user, a wrong key, bad permissions, a file saved by PowerShell, an old RSA signature and more. The message on our screen was identical every time (save for the list in brackets, which we’ll decode).
The good news? The server knows exactly what went wrong, and for most causes it writes it down. Once you know where to look, most of these take a minute to fix.
Most fixes online skip that step, and some even tell you to switch password logins back on. We’ll show you the log line for every cause instead, so you fix the real problem once.
In this guide you’ll learn
- A free error decoder: paste the message, get the cause and the fix
- What the brackets mean: (publickey), (publickey,password) and ()
- Where the real reason is: the server log and
ssh -v - 12 causes we reproduced, each with its exact log line
- The Windows traps: file encodings and key permissions
- GitHub, default users and old RSA keys, and fixes that make things worse
Chapter 1
The short answer
The same words appear in very different places. Find yours first:
| You see | It means | Go to |
|---|---|---|
| user@your-server: Permission denied (publickey) | Your server rejected every key you offered | Read the server log |
| [email protected]: Permission denied (publickey) | GitHub doesn’t recognise your key | GitHub fixes |
| Permission denied on a brand-new server | Often the wrong default user name | Default users |
| WARNING: UNPROTECTED PRIVATE KEY FILE! | Your PC refused to use the key | Windows fixes |
| Too many authentication failures | Your client offered too many keys | All causes |
Chapter 2
Decode your error
Paste the error from your terminal, the output of ssh -v, or lines from the server’s log. The decoder matches them against the messages we recorded while reproducing each cause. It runs only in your browser.
Paste something on the left. The more lines, the better: the server log usually names the cause.
Just the one line, Permission denied (publickey)? The decoder will tell you that’s not enough to go on. The next two chapters show how to get the lines that are.
Chapter 3
What the words in brackets mean
The part in brackets isn’t decoration. It’s the list of login methods the server still allows after rejecting yours. We changed the server’s settings and watched it change:
| Client shows | Server allows | What it tells you |
|---|---|---|
| Permission denied (publickey). | Keys only | Normal for a hardened server. Your key wasn’t accepted. |
| Permission denied (publickey,password). | Keys and passwords | Your key failed; the server would also take a password. |
| Permission denied (). | Nothing at all | Key login is switched off on the server (PubkeyAuthentication no). |
Empty brackets are rare and serious: no key will ever work until someone fixes the server config, usually through the server’s web console.
Chapter 4
Read the server’s log
On Ubuntu the SSH service is called ssh, and its log lives in the journal. Read it, or follow it live:
sudo journalctl -u ssh -n 50 # the last 50 lines sudo journalctl -fu ssh # follow live, then try to log in again
Older systems and many other distributions also write to /var/log/auth.log. Can’t log in to read it? On LiteKeep, open the web console on your server’s page and read it there. Next time, keep a working session open while you change anything.
Lines worth looking for
| Log line | Cause |
|---|---|
| Invalid user deploy from … | That user doesn’t exist on the server |
| Authentication refused: bad ownership or modes for file …/authorized_keys | authorized_keys is writable by others |
| Authentication refused: bad ownership or modes for directory … | ~/.ssh or your home folder is writable by others |
| User root from … not allowed because not listed in AllowUsers | The server config blocks that user |
| maximum authentication attempts exceeded for … | Too many keys offered |
| Connection closed by authenticating user … [preauth] | A key was tried and refused; the log doesn’t say why (see below) |
When the log says nothing useful
For a wrong key, a broken file or an old RSA signature, the default log only says Connection closed … [preauth]. Raise the detail with LogLevel VERBOSE and the server names the key it refused:
Failed publickey for root from 203.0.113.5 port 51034 ssh2: ED25519 SHA256:qqhU29HIyn/qAl0/yqZAa6sOXDf2OkegYnr4KJQ7OPM
Then compare fingerprints: run ssh-keygen -lf ~/.ssh/id_ed25519.pub on your PC and ssh-keygen -lf ~/.ssh/authorized_keys on the server. If the server’s list doesn’t include yours, the key isn’t installed. If the command fails outright, the file is damaged (chapter 7).
Chapter 5
Read your side with ssh -v
Add -v to your command and look for three kinds of lines:
debug1: Authentications that can continue: publickeydebug1: Offering public key: C:\Users\you\.ssh\id_ed25519 ED25519 SHA256:EMQ9pBYv… explicitdebug1: Authentications that can continue: publickeydebug1: No more authentication methods to try.[email protected]: Permission denied (publickey).
- Offering public key: which key it tried. Not the one you expected? Point at the right one with
-i, or addIdentityFileto your config. - No such identity / no key lines at all: SSH found no key. Check the file name and path.
- no mutual signature algorithm: an old RSA signature (chapter 9).
Chapter 6
The 12 causes we reproduced
Each row was caused on purpose on our test server, then fixed. Start with the row whose log line matches yours.
| Cause | Server log (default level) | Fix |
|---|---|---|
| Wrong user name | Invalid user … | Use the user the key was added for |
| Key not in authorized_keys | Connection closed … [preauth] | Add the .pub line for that user |
| authorized_keys writable by everyone (666) | bad ownership or modes for file | chmod 600 ~/.ssh/authorized_keys |
| ~/.ssh writable by everyone (777) | bad ownership or modes for directory …/.ssh | chmod 700 ~/.ssh |
| Home folder writable by everyone (777) | bad ownership or modes for directory /home/… | chmod 755 ~ |
| File saved as UTF-8 with BOM | Connection closed … [preauth] | Strip the BOM (chapter 7) |
| File saved as UTF-16 | Connection closed … [preauth] | Convert with iconv (chapter 7) |
| User not in AllowUsers | not allowed because not listed in AllowUsers | Add the user, sshd -t, reload |
| Key login switched off | Connection closed … (client shows “()”) | PubkeyAuthentication yes, reload |
| Too many keys offered | maximum authentication attempts exceeded | IdentitiesOnly yes and -i |
| RSA key signed with old SHA-1 | Connection closed … [preauth] | New Ed25519 key, or update the client |
| Private key readable by others (Windows) | Nothing: the client never sends it | icacls fix (chapter 10) |
Two things that did not break login
Plenty of guides blame these. In our test, both still worked:
MythWindows line endings (CRLF) in authorized_keys break it.
Our server accepted a file with CRLF endings. The encoding is what breaks it: a byte order mark or UTF-16 (chapter 7).
MythAny group-writable permission breaks it.
authorized_keys at 664 and a home folder at 775 both still worked, because the group contained only the owner. World-writable (666, 777) is what the server refuses.
Chapter 7
The Windows file-format trap
This one fools experienced people. You paste your key into authorized_keys, it looks perfect, and it never works. The cause is invisible: how the file was saved.
If you build the file on Windows and upload it, PowerShell may have saved it with a hidden byte order mark, or as UTF-16. Windows PowerShell 5.1’s Out-File -Encoding utf8 adds the mark, and -Encoding unicode writes UTF-16. In our test, both were rejected, and the server’s normal log said nothing.
How to tell
$ ssh-keygen -lf good.pub256 SHA256:qqhU29HIyn/qAl0/yqZAa6sOXDf2OkegYnr4KJQ7OPM litekeep-test (ED25519)$ ssh-keygen -lf ak_bomak_bom is not a public key file.$ file -b ak_bomUnicode text, UTF-8 (with BOM) text, with CRLF line terminators$ file -b ak_utf16leUnicode text, UTF-16, little-endian text, with CRLF line terminators
How to fix it
Both repairs worked on copies of our broken files:
# UTF-8 with a BOM: remove the 3 hidden bytes sed -i '1s/^\xEF\xBB\xBF//' ~/.ssh/authorized_keys # UTF-16: convert to UTF-8 iconv -f UTF-16 -t UTF-8 ~/.ssh/authorized_keys > /tmp/ak && mv /tmp/ak ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys # Confirm: it should print your key's fingerprint ssh-keygen -lf ~/.ssh/authorized_keys
Chapter 8
When the server’s config is the cause
Sometimes the key is fine and the server is set up to refuse it. Three settings matter most: PubkeyAuthentication, AuthorizedKeysFile and AllowUsers.
Your edit may be ignored
Modern Ubuntu reads extra files from /etc/ssh/sshd_config.d/, and settings there override the main file. The reason: for each setting, the first value read wins, and the drop-in folder is read near the top.
Some provider images of Ubuntu ship their own drop-ins, such as a 00- and a 99- file that both set PasswordAuthentication yes and PermitRootLogin yes. Change those settings in /etc/ssh/sshd_config and nothing happens. That’s why the next command matters.
See what the server really uses
sudo sshd -T | grep -Ei "^(pubkeyauthentication|passwordauthentication|permitrootlogin|authorizedkeysfile|allowusers) " ls /etc/ssh/sshd_config.d/
sshd -T prints the settings after every file is read. That’s the truth, whatever the files look like.
Change it safely
- Keep a working session openHow to check: Change SSH from a session that is already logged in, and don’t close it until a new one works.
- Edit the file that winsHow to check: A drop-in whose name sorts first, or the image’s own file. Then check with sshd -T.
- Test the configHow to check:
sudo sshd -tprints nothing when the config is valid. Run it before every restart. - Reload, don’t rebootHow to check:
sudo systemctl reload ssh. On Ubuntu 22.10 and later SSH can also be started by a socket; check withsystemctl status ssh.socketif a port change doesn’t take.
Chapter 9
Old RSA keys and old clients
In 2021, OpenSSH 8.8 stopped accepting one kind of RSA signature. It disables RSA signatures using the SHA-1 hash by default.
RSA keys themselves still work: in our test, a 3072-bit RSA key logged in fine with a modern client. What fails is an old client (old PuTTY, libraries, some CI tools) that can only sign the old way. We forced our client to do that, and ssh -v said:
debug1: Offering public key: C:\Users\you\.ssh\id_rsa RSA SHA256:qIRn50tc… explicitdebug1: send_pubkey_test: no mutual signature algorithmdebug1: No more authentication methods to try.[email protected]: Permission denied (publickey).
- Best fix: make an Ed25519 key with
ssh-keygen -t ed25519and add it to the server. - Or update the client so it signs RSA with SHA-256 or SHA-512, which OpenSSH has supported since version 7.2.
- DSA keys are finished: OpenSSH removed DSA support in version 10.0.
Chapter 10
Windows: the key your PC won’t use
On Windows, OpenSSH refuses a private key that other accounts can read. It never even reaches the server, so the server log stays empty.
WARNING: UNPROTECTED PRIVATE KEY FILE!Permissions for 'C:\Users\you\.ssh\id_ed25519' are too open.It is required that your private key files are NOT accessible by others.This private key will be ignored.[email protected]: Permission denied (publickey).
These two lines fixed it in our test:
icacls "$HOME\.ssh\id_ed25519" /inheritance:r
icacls "$HOME\.ssh\id_ed25519" /grant:r "${env:USERNAME}:R"Also on Windows: ssh-agent is disabled by default, so a key you added with ssh-add on another machine isn’t loaded here. Our Windows tutorial covers turning it on.
Chapter 11
[email protected]: Permission denied (publickey)
When Git says it, the server refusing you is GitHub, not yours. The checks, in order:
ssh -T [email protected] # should greet you by your GitHub user name ssh -vT [email protected] # if not: which key was offered? ssh-add -l -E sha256 # which keys the agent holds git remote -v # the remote must start with [email protected]:
- Always connect as
git, never your own name:[email protected]. - Add the public key to your account: Settings, SSH and GPG keys. Compare its fingerprint with
ssh-add -l -E sha256. - Using sudo?
sudo git pushruns as root, with root’s keys, not yours. Drop the sudo. - HTTPS remote? Then it isn’t using SSH at all. Switch with
git remote set-url origin [email protected]:user/repo.git.
Chapter 12
New servers: the default user name
Many cloud images don’t let you log in as root, and each has its own default user. Log in as the wrong one and the key is refused, however right it is.
| Image | User |
|---|---|
| Ubuntu cloud images | ubuntu |
| Debian cloud images | debian or admin |
| Rocky Linux | rocky |
| Fedora | fedora |
| Bitnami images | bitnami |
On LiteKeep, a new server starts with root. Add your public key when you deploy, log in as root@your-server-ip, and it works first time. Your welcome email and the server’s page show the details.
Chapter 13
Fixes that make things worse
You’ll see these suggested all over the web. Each one hides the problem and opens a new one.
MythTurn PasswordAuthentication back on.
That gets you in by bypassing the key, and reopens the door to password guessing. Our own server saw more than 14,000 attempts in three days. Fix the key, keep passwords off.
Mythchmod 777 the .ssh folder so SSH can read it.
The opposite: the server refuses world-writable folders. We tested it. Use 700 and 600.
MythSet StrictModes no.
It switches off the permission check for every user, so anyone who can write your files can add their own key.
MythRun setenforce 0 on RHEL or Fedora.
That turns SELinux off. If SELinux labels are the issue, restorecon -Rv ~/.ssh fixes the labels and keeps the protection.
Chapter 14
Locked out completely?
If no key works and passwords are off, you need a way in that doesn’t use SSH.
- The web console: a browser window onto the server’s screen. Every LiteKeep server has one on its page in your account. Log in there, read the log, fix the file.
- A snapshot: took one before the change? Roll back to it from the server’s Snapshots tab.
- Reinstall as a last resort, with your key added, then restore from backup.
Next time, change SSH the way our VPS security guide does it: a second session kept open, sshd -t before every reload, and a test login before you close anything.
Now it’s your move
“Permission denied (publickey)” is one sentence covering a dozen problems. The server almost always knows which one.
Read its log, match the line, fix that one thing. And if you’re setting up keys for the first time on Windows, our step-by-step tutorial avoids most of these before they happen.
Tired of servers you can’t get back into? Deploy a Lite 2: your key goes in at deploy, and the web console is one click away if SSH ever refuses you.