Skip to content
DevOps2026-09-084 min read

Permission denied (publickey): 6 Reasons Git Push Fails Over SSH (and the Fix for Each)

Symptom: git refuses to talk to the remote

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.

One-line diagnosis: SSH authentication failed — the server doesn't recognize the public key you presented. This has nothing to do with passwords (publickey auth doesn't use one). Either the key in your hand doesn't match any lock registered on the server, or you never handed over a key at all.

First step: test auth directly with ssh -T

Skip git and test the SSH channel itself — you'll get the cleanest error:

ssh -T git@github.com
# Success: Hi yourname! You've successfully authenticated...
# Failure: git@github.com: Permission denied (publickey).

# Add -v for the full story: which keys were offered, which auth the server accepts
ssh -vT git@github.com 2>&1 | grep -E 'Offering|identity file|denied'

The Offering public key: /Users/you/.ssh/id_xxx lines in the -v output are the key evidence — they list the keys actually presented. If the one you thought you were using isn't there, jump straight to cause 2.

Six causes, ranked by frequency

1. No key on this machine (most common on a new laptop)

ls ~/.ssh/
# id_ed25519 / id_ed25519.pub or id_rsa / id_rsa.pub → you have one
# nothing → generate one
ssh-keygen -t ed25519 -C "your_email@example.com"
# accept the defaults (or set a passphrase), then start the agent and load it
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

Then add the contents of the .pub file (public keys only — the private key never leaves your machine) to GitHub: Settings → SSH and GPG keys → New SSH key.

2. Key exists, but the agent isn't offering it

ssh-add -l
# "The agent has no identities." → not loaded
ssh-add ~/.ssh/id_ed25519

On macOS, put the key metadata in ~/.ssh/config and skip the manual add forever:

Host github.com
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_ed25519

3. Public key never added to the platform (or added to the wrong account)

GitHub keys are account-scoped: a key registered under account A gets rejected for account B's repos. Another trap: the same public key is already bound to a different GitHub account — GitHub doesn't allow one key on multiple accounts, and the same applies to deploy keys. For multi-account setups, see cause 4.

Company GitLab, Gitee, and self-hosted servers each have their own key-upload page — make sure you added it to the platform you're actually pushing to.

4. Multiple accounts/keys: the wrong key gets offered

With a work key and a personal key on the same machine, SSH tries them in order and often presents the wrong one. Route by host alias in ~/.ssh/config:

# Personal GitHub
Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_personal
  IdentitiesOnly yes

# Work GitHub account via an alias
Host github-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work
  IdentitiesOnly yes

IdentitiesOnly yes is the critical line — it forces SSH to offer only the specified key instead of trying every key it can find. Then use the alias in your remote URL:

git remote set-url origin git@github-work:company/repo.git

5. Deploy keys have a permission boundary

A public key added under a repo's Settings → Deploy keys is valid for that repo only: cloning a different repo with it, or pushing when the key was added without write access, both end in publickey rejection. The classic CI trap: one runner using one deploy key to pull many repos — use organization-level deploy keys or a machine-user account instead.

6. Wrong remote URL (https and ssh mixed up)

git remote -v
# origin  git@github.com:user/repo.git     → SSH; debug with the methods above
# origin  https://github.com/user/repo.git → HTTPS; errors ask for a password/token, not publickey

Case mismatches, misspelled org names, and a missing .git suffix all blur the line between "repo not found" and "auth failed". Also note: if a GitHub organization enforces SSO, a personal key still needs a one-time authorization for that org (SSO → Authorize).

Why does it say publickey when I never configured keys?

The word in parentheses is the list of auth methods the server permits. If you see Permission denied (publickey,password), both methods were tried and both failed — SSH attempts each method the server allows before giving up. Read the parentheses to see which doors exist.

Checklist

  1. ssh -T git@github.com — direct test, cleanest error message
  2. ssh -vT ... | grep Offering — which keys were actually presented?
  3. ls ~/.ssh/ + ssh-add -l — does the key exist? is it loaded?
  4. Is the public key registered on the right platform, account (or repo deploy key)?
  5. Multiple keys: ~/.ssh/config with per-host aliases + IdentitiesOnly yes
  6. git remote -v — check the URL spelling and protocol (ssh vs https)

Provided by ToolVault. Related tools: Linux Cheatsheet, Password Generator, JWT Decoder. Related reading: npm registry mirror guide, Port already in use. See the homepage for more developer tools.


Advertisement