Skip to main content
DevOpsbeginner

Fix "Permission denied (publickey)" in Git and SSH

Fix `git@github.com: Permission denied (publickey).` in Git and SSH. Diagnose with ssh -T, load the right key, and repair agent and permission problems.

8 min readUpdated August 2026

If Git or SSH stops with Permission denied (publickey)., the full output usually looks like this:

git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

The second half of that message is misleading. The repository almost certainly exists and your access rights are probably fine. Permission denied (publickey) means the server accepted your TCP connection, asked for a public key, and rejected every key your client offered — so it hung up before authentication finished. The fatal: line is just Git reporting that the transport died.

Test authentication on its own, without Git in the way:

ssh -T git@github.com

A working setup prints your username:

Hi yourname! You've successfully authenticated, but GitHub does not provide shell access.

That "does not provide shell access" wording is the success case, not a failure. If you get Permission denied (publickey). instead, work down the list below in order.

Why This Happens

There are only four real causes, in rough order of frequency:

  1. No key exists — a fresh machine or a fresh user account has an empty ~/.ssh.
  2. The key is not being offered — it exists, but it is not loaded in the agent and has a non-default filename, so SSH never tries it.
  3. The public key is not registered on the server — the key is offered, and the server does not recognise it.
  4. File permissions are too open — OpenSSH refuses to use a private key other users can read, and falls back to offering nothing.

Fix 1: Check Whether You Have a Key At All

ls -la ~/.ssh

You are looking for a matching pair, such as id_ed25519 (private) and id_ed25519.pub (public). Older setups use id_rsa / id_rsa.pub.

If the directory is empty or does not exist, generate a key:

ssh-keygen -t ed25519 -C "your@email.com"

Press Enter to accept the default path. Set a passphrase if you want one — the agent will remember it. On a legacy system that rejects Ed25519, use ssh-keygen -t rsa -b 4096 -C "your@email.com" instead.

Fix 2: Register the Public Key on the Server

Copy the public key — the file ending in .pub:

cat ~/.ssh/id_ed25519.pub

That prints one line beginning ssh-ed25519 AAAA.... Paste it into your host's key settings:

  • GitHub — Settings → SSH and GPG keys → New SSH key
  • GitLab — Preferences → SSH Keys
  • Bitbucket — Personal settings → SSH keys
  • Your own server — append it to ~/.ssh/authorized_keys on that machine

Never paste the file without the .pub extension. That is your private key. If you have already uploaded one, delete it from the service and generate a fresh pair — a private key that has left your machine must be treated as compromised.

Advertisement

Fix 3: Load the Key Into the SSH Agent

A key that exists but is not loaded will not be offered. Check the agent:

ssh-add -l

If it prints The agent has no identities., add your key:

ssh-add ~/.ssh/id_ed25519

On macOS, store the passphrase in the keychain so it survives reboots:

ssh-add --apple-use-keychain ~/.ssh/id_ed25519

If ssh-add itself fails with Could not open a connection to your authentication agent, the agent is not running:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

This is the cause behind the classic "it worked yesterday, now it doesn't" report — the agent is cleared on reboot.

If you use a password manager as your agent rather than OpenSSH's own, the diagnosis changes: an empty ssh-add -l or an agent refused operation error usually means the integration itself has stopped serving keys, not that your key is missing. See 1Password SSH agent not working for that path.

Fix 4: Repair File Permissions

OpenSSH refuses to use an over-permissive private key and skips it silently as far as the server is concerned:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub

If the failure is on a server you are logging in to, the same rule applies at the far end — ~/.ssh must be 700 and ~/.ssh/authorized_keys must be 600, both owned by the logging-in user. sshd ignores group- or world-writable files, and the client-side symptom is identical to having no key.

Fix 5: Point SSH at the Right Key Explicitly

If you use a non-default filename, or several keys for different hosts, tell SSH which to use in ~/.ssh/config:

Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work
  IdentitiesOnly yes

IdentitiesOnly yes matters more than it looks. Without it, SSH offers every key it knows about, and some servers close the connection after a handful of failed attempts — so the right key never gets tried. That produces Permission denied (publickey) even though the correct key is sitting right there.

Verify the Fix

Re-run the authentication test:

ssh -T git@github.com

If it still fails, run it verbose and read which keys were actually offered:

ssh -vT git@github.com

Look for lines like:

debug1: Offering public key: /Users/you/.ssh/id_ed25519 ED25519 SHA256:abc123...
debug1: Authentications that can continue: publickey

If your key never appears in an Offering public key line, the problem is Fix 3 or Fix 5 — the client is not presenting it. If it is offered and the server still refuses, the problem is Fix 2 — that key is not registered on the account.

Once ssh -T succeeds, confirm your remote is actually using SSH:

git remote -v

An SSH remote looks like git@github.com:user/repo.git. If yours starts with https://, Git was never using SSH, and your key setup was not the problem. Switch it if you want SSH:

git remote set-url origin git@github.com:user/repo.git

Prevention

  • Use one key per machine, not one key copied across machines. Revoking a lost laptop then means deleting one key, not rotating everything.
  • Add IdentitiesOnly yes to each ~/.ssh/config host block once you have more than one key.
  • On macOS, use --apple-use-keychain so a reboot never costs you an hour.
  • Back up ~/.ssh/config, not your private keys. Keys are cheap to regenerate; a working config is the part worth keeping.

If you need to work around SSH entirely on a machine you do not control, switching the remote to HTTPS and authenticating with a personal access token is a legitimate fallback — it moves the credential from a key file to a token, with the same access.

Frequently Asked Questions

Find answers to common questions

The server accepted your connection but rejected every key your SSH client offered, so it closed the session before you were authenticated. It is an authentication failure, not a network or repository-not-found failure. Either you have no key, the key you have is not loaded, or the matching public key is not registered on the server.

Run 'ssh -T git@github.com' to test authentication on its own. If it fails, check for a key with 'ls -la ~/.ssh', create one with 'ssh-keygen -t ed25519 -C "your@email.com"' if there is none, add the public key to your GitHub account under Settings then SSH and GPG keys, and load the private key with 'ssh-add ~/.ssh/id_ed25519'.

You most likely added the wrong file. GitHub needs the contents of the .pub file, not the private key. Run 'cat ~/.ssh/id_ed25519.pub' and paste that single line. If you pasted a private key, delete it from GitHub immediately and generate a new key pair, because that key is now compromised.

Run 'ssh -vT git@github.com' and read the 'Offering public key' lines. They list every key the client tries, in order. If your key never appears, it is not in the agent and not being picked up from ~/.ssh, which is what the -i flag or an IdentityFile entry in ~/.ssh/config fixes.

Your key was loaded into the ssh-agent, and the agent was cleared when the machine restarted. Run 'ssh-add -l' to confirm the agent is empty, then 'ssh-add ~/.ssh/id_ed25519' to reload it. On macOS add 'ssh-add --apple-use-keychain' so the passphrase is remembered across reboots.

Yes. OpenSSH ignores a private key that is readable by other users and prints 'UNPROTECTED PRIVATE KEY FILE!' before falling back to no key at all. The private key must be 600 and the ~/.ssh directory 700. Run 'chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_ed25519' to fix it.

The same causes apply, plus one more: your public key must be in ~/.ssh/authorized_keys on the remote server, and that file must be 600 with a 700 ~/.ssh directory owned by your user. Sshd silently refuses group-writable or world-writable files, which looks identical to having no key at all.

It is a valid workaround: 'git remote set-url origin https://github.com/user/repo.git' avoids SSH entirely. You will then be prompted for a personal access token instead of a password. For a machine you use every day, fixing SSH once is less friction than managing tokens.

Authentication is working, so the problem is authorization or the remote URL. Check 'git remote -v' — if the remote points at a different host or a repo you lack write access to, the push fails for a different reason. A successful ssh -T always ends with 'but GitHub does not provide shell access', which is expected, not an error.