You run ssh user@server and instead of a login prompt, you see a block of red text ending in “Permission denied (publickey).” Or you see SSH’s unprotected private key warning. SSH ignores your key and falls back to password authentication — which may be disabled on the server, leaving you locked out. This is not a bug. It is a deliberate security check, and it exists because a readable private key is a compromised private key. This guide explains why SSH checks key permissions, what the correct modes are, how to fix them, and what to check when fixing the key does not fix the connection.

SSH validates the permissions of your private key and the ~/.ssh directory before it uses them. If either is accessible by other users on the system, SSH aborts. The check exists for three reasons:

  • A world-readable private key can be copied by any user. Once copied, that user can impersonate you.
  • A writable ~/.ssh directory lets an attacker drop their own public key into authorized_keys. They can then log in as you without your key at all.
  • A world-writable authorized_keys file lets anyone add their own key to your account. Same result: unauthorized access.

SSH trusts your key only if no one else can read or modify it. That is why the check is automatic and cannot be safely disabled. If you see the warning, SSH is doing exactly what it was designed to do: refusing to use a key that other users could read.

The correct permissions

Here is the complete permission table for the ~/.ssh directory and its contents. The two that must be locked down are the directory itself and the private key. The home directory matters too — SSH checks it, and if it is group- or world-writable, SSH may refuse keys even when ~/.ssh itself is correct.

PathModeSymbolicWhy
~/.ssh (directory)700rwx------Only you can list or create files in the directory
~/.ssh/id_ed25519 (private key)600rw-------Secret; readable and writable only by you
~/.ssh/id_ed25519.pub (public key)644rw-r--r--Not secret; world-readable is fine
~/.ssh/authorized_keys600rw-------Controls who can log in as you
~/.ssh/known_hosts644rw-r--r--Host keys you trust; not secret
~ (home directory)755 or 700rwxr-xr-xMust not be group- or world-writable
The directory and private keys are the two that must be locked down. The home directory must not be writable by others.

How to fix it

Check the current modes first:

stat -c '%a %A %n' ~/.ssh ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.pub ~/.ssh/authorized_keys ~

Then fix what is wrong:

# Directory must be 700
chmod 700 ~/.ssh

# Private key must be 600
chmod 600 ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_rsa

# Public key can be 644
chmod 644 ~/.ssh/id_ed25519.pub
chmod 644 ~/.ssh/id_rsa.pub

# authorized_keys must be 600
chmod 600 ~/.ssh/authorized_keys

# Home directory must not be group- or world-writable
chmod go-w ~

I fix the ~/.ssh directory first, then the private key, then verify the home directory is not group- or world-writable. After fixing, try the connection again from a new terminal. Keep your existing SSH session open until you confirm the new one works — you do not want to lock yourself out of a remote server while debugging.

Common causes

Permissions usually become too open because of one of these:

  • Copying a key from another machine. A USB drive, email attachment, or network copy may preserve a permissive umask, creating a world-readable private key.
  • Running chmod -R 755 over your home directory. This sets every file to 755, including your private keys.
  • Creating ~/.ssh with the default umask (often 022). The directory gets 755 instead of 700.
  • Extracting a key from an archive. Tar and zip archives can store world-readable modes.
  • Windows/WSL filesystem issues. If your key lives on a Windows filesystem mounted in WSL, Linux permission bits may not apply, and SSH may refuse the key or behave unpredictably.

On WSL, if you cannot change permissions because the underlying Windows filesystem does not support them, copy the key into the WSL filesystem (~/.ssh on the Linux side) and fix the permissions there. The permission check happens on the Linux side, so the key must live on a filesystem that supports Linux permission bits.

Prevention

Set a restrictive umask before generating keys so new files are private by default:

umask 077
mkdir -p ~/.ssh
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519

umask 077 makes new files mode 600 and new directories mode 700. After generating the key, set the public key to 644 explicitly if you want it world-readable. The private key stays 600.

When copying keys between machines, fix permissions on the destination immediately after copying, before you try to use them:

scp ~/.ssh/id_ed25519 user@host:.ssh/
ssh user@host "chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_ed25519 && chmod 644 ~/.ssh/id_ed25519.pub"

I consider umask 077 the most important prevention step because it stops the problem from recurring. Fixing chmod 600 on an already-too-open key fixes today’s problem; umask 077 prevents it from happening again on the next key you generate.

When fixing permissions is not enough

If you have corrected the permissions and SSH still will not connect, check these in order:

  • Is the public key in ~/.ssh/authorized_keys on the server? The server needs your public key, not your private key. Private keys never belong on the server.
  • Is password authentication disabled on the server? If PasswordAuthentication no is set and your key is rejected, you have no fallback.
  • Is PermitRootLogin no set, and are you trying to log in as root? Use a normal user with sudo instead.
  • Is the server’s sshd_config pointing to a different AuthorizedKeysFile path? Some deployments use /etc/ssh/authorized_keys/%u instead of ~/.ssh/authorized_keys.
  • Run SSH with verbose output to see what is happening:
ssh -v user@server

Look for lines mentioning “Offering public key” and “Authentications that can continue.” If SSH never offers your key, the client-side permissions are still wrong. If it offers the key and the server rejects it, the server-side authorized_keys or sshd_config is the problem.

I use ssh -v to distinguish between client-side and server-side problems before I start changing configuration on either side. Changing both at once makes it impossible to tell which change fixed the issue, and you may introduce new problems without solving the original one.

The questions worth asking

  • Is the private key mode 600?
  • Is the ~/.ssh directory mode 700?
  • Is the home directory group- or world-writable?
  • Is the public key installed in authorized_keys on the server?
  • Does ssh -v show SSH offering the key?

References

Related Tools

Try these companion tools on DevStackIO Tools: