Dev Tools

Fix: SSH 'Permission denied (publickey)' after key setup

SSH refuses to connect with publickey even though the key is uploaded. Here are the real causes and specific fixes for each.

You added your public key to the server, but SSH still refuses:

someuser@1.2.3.4: Permission denied (publickey).

The key exists, authorized_keys looks right, and the same key works elsewhere. Here are the six real causes and the specific fix for each.

Diagnose first

Always start with verbose output:

ssh -v someuser@1.2.3.4

The -v (or -vvv for maximum verbosity) shows exactly which keys the client offered, which authentication methods the server accepted, and where authentication broke.

Read every line starting with debug1: Offering public key and debug1: Authentications that can continue. The failure mode is usually visible in that output.

Cause 1 — Wrong permissions on the .ssh directory or authorized_keys

OpenSSH refuses to use authorized_keys if it’s readable by anyone except the owner. This is intentional but silent — the server just says “publickey denied” without explanation.

Symptom: verbose output shows Authentications that can continue: publickey but no key succeeds.

Fix on the server:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R $USER:$USER ~/.ssh

Check the sshd log to confirm this was the issue:

sudo tail -50 /var/log/auth.log         # Debian/Ubuntu
sudo tail -50 /var/log/secure           # RHEL/CentOS/Amazon Linux

Look for a message like: Authentication refused: bad ownership or modes for directory /home/user/.ssh.

Cause 2 — SSH client not offering the right key

If you have multiple SSH keys, the client tries them in order and gives up after 5 or 6 attempts (MaxAuthTries). If the right key is 7th on the list, it never gets offered.

Diagnose:

ssh -v someuser@1.2.3.4 2>&1 | grep "Offering public key"

If the key you expect isn’t listed, or is listed after 6 others, this is the cause.

Fix — explicitly point to the right key:

ssh -i ~/.ssh/id_ed25519_specific someuser@1.2.3.4

Or configure it permanently in ~/.ssh/config:

Host prod-server
    HostName 1.2.3.4
    User someuser
    IdentityFile ~/.ssh/id_ed25519_specific
    IdentitiesOnly yes

IdentitiesOnly yes is important — without it, ssh still tries every key in the agent before yours.

Cause 3 — Public key on server doesn’t match your private key

The authorized_keys line came from copy-paste that broke on a newline, or you uploaded the wrong key (id_rsa vs id_ed25519, or a different machine’s key).

Diagnose — compare fingerprints:

On your machine:

ssh-keygen -lf ~/.ssh/id_ed25519.pub

On the server:

ssh-keygen -lf ~/.ssh/authorized_keys

Fingerprints should match line-for-line.

Fix — re-upload the correct key:

ssh-copy-id -i ~/.ssh/id_ed25519.pub someuser@1.2.3.4

If password auth is disabled and you can’t ssh in at all, use the cloud console (AWS EC2 “Connect”, GCP serial console) to fix authorized_keys directly.

Cause 4 — Server disabled public key authentication

Someone tightened sshd_config and set PubkeyAuthentication no, or restricted AllowUsers / AllowGroups.

Diagnose (requires shell access via alternate method):

sudo grep -Ei 'PubkeyAuthentication|AllowUsers|AllowGroups|PermitRootLogin' /etc/ssh/sshd_config

Fix — flip the setting back:

sudo sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sudo systemctl reload sshd

For AllowUsers, add your user:

sudo sed -i '/^AllowUsers/ s/$/ someuser/' /etc/ssh/sshd_config
sudo systemctl reload sshd

Cause 5 — SELinux context on ~/.ssh is wrong

On RHEL, CentOS, Fedora, and Amazon Linux, SELinux blocks sshd from reading authorized_keys if the file’s security context is wrong (common after restoring from backup or copying files across systems).

Symptom: /var/log/audit/audit.log shows AVC denials mentioning authorized_keys.

Fix — restore correct SELinux contexts:

sudo restorecon -Rv ~/.ssh

Verify:

ls -Z ~/.ssh

Files should show unconfined_u:object_r:ssh_home_t:s0 (or similar ssh_home_t).

Cause 6 — Newer key algorithm not supported by old sshd

Ed25519 keys don’t work against OpenSSH < 6.5. Ed25519-sk (hardware keys) need OpenSSH 8.2+. RSA-SHA2 signatures need >= 7.2.

Diagnose:

ssh -V                                  # your client version
ssh -v someuser@host 2>&1 | grep "remote software"   # server version

Fix — one of:

  • Upgrade OpenSSH on the server: apt install openssh-server or yum update openssh-server
  • Use an RSA key instead: ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_legacy
  • Set explicit algorithms: ssh -o PubkeyAcceptedAlgorithms=+ssh-rsa host

The universal SSH publickey debug flow

Every “Permission denied (publickey)” case, in order:

# 1. Verbose output — reveals most causes
ssh -v someuser@host

# 2. Check server-side sshd logs
sudo tail -50 /var/log/auth.log

# 3. Verify file permissions on server
ls -la ~/.ssh

# 4. Compare key fingerprints
ssh-keygen -lf ~/.ssh/id_ed25519.pub
ssh-keygen -lf ~/.ssh/authorized_keys

# 5. Check sshd_config
sudo grep -Ei 'PubkeyAuth|AllowUsers' /etc/ssh/sshd_config

# 6. SELinux (RHEL family only)
sudo ausearch -m AVC -ts recent | grep ssh

Ninety percent of publickey failures resolve at step 1-3.

Prevention

For every new server:

  • Deploy authorized_keys via configuration management (Ansible, cloud-init) — never manual copy-paste
  • Fixed permissions in the playbookchmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys on every run
  • ~/.ssh/config with explicit IdentityFile per host — no relying on ssh’s guess
  • Central key rotation — quarterly key roll, tracked in a doc, verified with a canary connection
  • Ed25519 keys default — smaller, faster, more secure than RSA
  • Fail2ban or sshguard — block brute-force attempts that fill logs and mask real failures

Bottom line

Permission denied (publickey) is one of the noisiest useful error messages in Linux. The information IS there — you just need ssh -v on the client, sshd logs on the server, and to check file permissions. Ninety percent of cases are wrong ownership on ~/.ssh, key not offered by client, or key/authorized_keys mismatch. Fix those first, then work down the list.

Recommended

DevOps YAML Pack

36 production-ready configs — Kubernetes, Docker Compose, GitHub Actions, Terraform, Helm, Ansible. Every file heavily commented. Copy, paste, ship.

Get the pack — ₹499 →
Never miss an article