# How to Fix "Permission denied (publickey)" in SSH

`Permission denied (publickey).` is the server telling you two things: it only accepts key-based logins, and none of the keys your client offered were accepted. The cause is almost always one of a handful of things — and `ssh -v` will tell you which.

## Step 1: watch the handshake

```bash
ssh -v user@host
```

The lines that matter:

```
debug1: Authentications that can continue: publickey
debug1: Offering public key: /home/you/.ssh/id_ed25519 ED25519 SHA256:…
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
```

You now know which keys were offered and that the server refused each one. If the key you expected isn't in the list, the problem is on your side; if it was offered and refused, it's on the server's.

## Wrong username

Each cloud image has its own default user: `ubuntu` on Ubuntu, `ec2-user` on Amazon Linux, `admin` on Debian AMIs, and often `root` elsewhere. For GitHub and GitLab, the user is always `git`:

```bash
ssh -T git@github.com
# Hi your-name! You've successfully authenticated, but GitHub does not provide shell access.
```

## The right key isn't being offered

Point ssh at the key explicitly:

```bash
ssh -i ~/.ssh/my-server-key user@host
```

To make that permanent, add a block to `~/.ssh/config`:

```
Host myserver
  HostName 203.0.113.10
  User ubuntu
  IdentityFile ~/.ssh/my-server-key
  IdentitiesOnly yes
```

`IdentitiesOnly yes` stops ssh offering every key in your agent first. Servers give up after a few failed attempts, so an agent holding many keys can trigger *Too many authentication failures* before the right one is tried.

## Your public key isn't on the server

The server checks `~/.ssh/authorized_keys` for the user you log in as. Add your public key with:

```bash
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
```

If you can't log in at all, add it through your cloud provider's console or a recovery shell.

## Permissions on the server are too open

With its default `StrictModes`, sshd ignores `authorized_keys` if the files are writable by others. The server's auth log says so explicitly — `Authentication refused: bad ownership or modes` in `/var/log/auth.log` (or `journalctl -u ssh`). Fix the modes:

```bash
chmod go-w ~                     # home directory: not writable by group or others
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
```

([700](/chmod/700) and [600](/chmod/600) explained.)

## Permissions on your private key are too open

The client has its own check. If your private key is readable by other users, ssh refuses to use it:

```
WARNING: UNPROTECTED PRIVATE KEY FILE!
Permissions 0644 for '/home/you/.ssh/id_ed25519' are too open.
```

```bash
chmod 600 ~/.ssh/id_ed25519   # or 400, read-only
```

Public keys (`.pub`) can stay at [644](/chmod/644); only the private half must be private. AWS's `.pem` keys need the same treatment — that's why its guides say [chmod 400](/chmod/400).

## The agent doesn't have your key

If you rely on `ssh-agent`, check what it holds:

```bash
ssh-add -l
ssh-add ~/.ssh/id_ed25519
```

On macOS, `ssh-add --apple-use-keychain ~/.ssh/id_ed25519` stores the passphrase in the Keychain so it survives reboots.

## Old RSA keys and old servers

OpenSSH 8.8 (2021) disabled RSA signatures using SHA-1 (`ssh-rsa`) by default. A modern client connecting to an old server that only supports `ssh-rsa`, or an old client meeting a hardened server, can end in *Permission denied* with an RSA key that worked for years. The clean fix is a modern key:

```bash
ssh-keygen -t ed25519 -C "you@example.com"
```

Then add the new public key to the server or to GitHub.

## Quick checklist

1. `ssh -v` — which keys are offered?
2. Right user for this server?
3. Right key — `-i` or `IdentityFile`, with `IdentitiesOnly yes`?
4. Public key in the server's `authorized_keys`?
5. Server: home not group-writable, `~/.ssh` 700, `authorized_keys` 600.
6. Client: private key 600 or 400.
7. Still stuck with an old RSA key? Generate an ed25519 key.

For any other permission combination, the [chmod calculator](/chmod) shows exactly who can do what.
