GitHub / git permission denied (publickey) — how to fix

# 1. Start ssh-agent and load your key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

# 2. Copy your public key — paste it into GitHub / GitLab
cat ~/.ssh/id_ed25519.pub
#    GitHub  → Settings → SSH and GPG keys → New SSH key
#    GitLab  → Preferences → SSH Keys → Add new key

# 3. Verify the connection
ssh -T [email protected]
# Expected: Hi <username>! You've successfully authenticated...

You run git push, git pull, or git clone over SSH and GitHub shows a publickey error such as:

[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

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

Git cannot authenticate because it cannot find or use your SSH private key. This is the common GitHub "permission denied publickey" failure.

The SSH connection reached the host but no accepted key was offered

SSH authentication happens before Git can read repository history. GitHub receives one or more public-key offers from your SSH client and accepts a connection only when a matching public key is registered to an account that can access the repository. The error can therefore come from a missing key, an unloaded key, the wrong account, the wrong host alias, or missing repository permission.

Do not regenerate keys immediately. First identify the remote host and the keys your client is actually offering. Replacing a working key can break access to other repositories without fixing the real cause.

Check the remote, agent, and SSH handshake in that order

The remote URL tells you whether this repository uses SSH at all. The agent listing shows which identities are currently loaded. Verbose SSH output then shows which configuration files and identity files are selected. The diagnostic command does not push code or change the repository.

git remote -v
ssh-add -l
ssh -vT [email protected]

Use a key file that exists and protect its permissions

Private keys must remain on your computer. Register only the matching .pub file with the hosting provider. OpenSSH may ignore a private key that is readable by other users, so keep the ~/.ssh directory and key permissions restrictive.

ls -la ~/.ssh
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l

Give each GitHub account an explicit SSH host alias

When personal and work accounts use different keys, relying on whichever key the agent offers first is fragile. Define one host alias per account, bind it to a specific identity, and use that alias in the repository remote URL. IdentitiesOnly yes prevents SSH from trying unrelated agent keys first.

# ~/.ssh/config
Host github-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work
  IdentitiesOnly yes

# Repository remote
git remote set-url origin git@github-work:company/repository.git
ssh -T git@github-work

Successful SSH authentication does not guarantee repository permission

If ssh -T succeeds but clone, fetch, or push still fails, verify the owner and repository path in git remote -v. Confirm that the authenticated account is a collaborator or organization member and that any organization single sign-on requirement has been authorized for the key. Read access may permit fetch while branch protection or role settings still block push.

Test authentication, remote reads, then the intended Git operation

Verify one layer at a time. A successful host test confirms the account identity. git ls-remote confirms that account can read this repository without altering it. Only then retry pull or push. This keeps authentication failures separate from later history errors such as non-fast-forward rejection.

ssh -T [email protected]
git ls-remote origin HEAD
git fetch origin

No SSH key exists yet

# Check if you already have a key
ls ~/.ssh/id_*.pub

# If nothing is listed, generate one
ssh-keygen -t ed25519 -C "[email protected]"

macOS: key lost after reboot

On macOS the ssh-agent resets on restart. Add this to ~/.ssh/config to load the key automatically via Keychain:

Host *
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_ed25519

Remote URL is HTTPS, not SSH

If the remote URL starts with https://, Git uses a password/token prompt instead of SSH keys.

# Check current URL
git remote -v

# Switch to SSH
git remote set-url origin [email protected]:user/repo.git