Fix Git “Permission Denied (publickey)” Error in 3 Minutes
The Git error:
Permission denied (publickey).
fatal: Could not read from remote repository.
means your SSH client tried to authenticate to the Git server using SSH keys, but the server rejected all keys offered (or no key was offered). This tutorial gets you from error → working connection quickly, while also explaining what is happening under the hood so you can fix it permanently.
0) Confirm what you’re actually using: SSH vs HTTPS
This error is SSH-specific. If your remote URL is HTTPS, you’ll get different errors (password/token issues).
Check your remote:
git remote -v
Typical SSH remotes look like:
- GitHub:
git@github.com:OWNER/REPO.git - GitLab:
git@gitlab.com:OWNER/REPO.git - Bitbucket:
git@bitbucket.org:OWNER/REPO.git
If you see HTTPS like https://github.com/OWNER/REPO.git, then you are not using SSH. You can still switch to SSH later, but this tutorial assumes SSH.
1) The 3-minute quick fix checklist (do these in order)
Step 1 — Verify you have an SSH key
List keys in the default location:
ls -al ~/.ssh
Look for files like:
id_ed25519andid_ed25519.pub(recommended)id_rsaandid_rsa.pub(older)
If you do not have any key pair, create one:
ssh-keygen -t ed25519 -C "your_email@example.com"
Press Enter to accept the default path (~/.ssh/id_ed25519). Add a passphrase if you want better security.
Step 2 — Start the SSH agent and load your key
On macOS/Linux:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
If you used RSA:
ssh-add ~/.ssh/id_rsa
On Windows (PowerShell), you can do:
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
Step 3 — Add your public key to your Git host (GitHub/GitLab/Bitbucket)
Copy the public key to clipboard:
macOS:
pbcopy < ~/.ssh/id_ed25519.pub
Linux (with xclip):
xclip -selection clipboard < ~/.ssh/id_ed25519.pub
Windows (PowerShell):
Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | Set-Clipboard
Then paste into your Git provider’s SSH keys page:
- GitHub: Settings → SSH and GPG keys → New SSH key
- GitLab: Preferences → SSH Keys
- Bitbucket: Personal settings → SSH keys
Step 4 — Test authentication directly (most important)
Run:
ssh -T git@github.com
Or for GitLab:
ssh -T git@gitlab.com
Or Bitbucket:
ssh -T git@bitbucket.org
Expected outcomes:
- Success (GitHub example):
- “Hi USERNAME! You’ve successfully authenticated…”
- Still failing:
- “Permission denied (publickey).” → continue with the deeper diagnostics below.
Step 5 — Retry Git
git fetch
# or
git pull
# or
git push
If it works, you’re done. If not, the rest of this tutorial explains the common failure modes and how to prove which one you have.
2) What “Permission denied (publickey)” actually means
When you run git fetch over SSH, Git runs something like:
ssh git@github.com git-upload-pack 'OWNER/REPO.git'
SSH then tries to authenticate. With public key authentication:
- Your client offers one or more public keys.
- The server checks if any offered public key is registered/authorized for that account.
- If it recognizes a key, it sends a challenge.
- Your client proves it has the matching private key by signing the challenge.
- Server grants access.
The error appears when:
- Your client did not offer any usable key (no key loaded, wrong path, wrong permissions, wrong SSH config).
- Your client offered keys, but the server does not know them (public key not added to account, added to wrong account, or wrong server).
- Your client offered a key, server recognized it, but the client could not use the private key (permissions, passphrase prompt blocked, agent issues).
- You’re connecting as the wrong user or to the wrong host (e.g., enterprise GitHub, self-hosted GitLab, wrong hostname in remote URL).
- Your repo access is denied even though SSH auth succeeded (different error messages often, but sometimes looks similar).
3) Use SSH debug output to see what key is being used
If the quick checklist didn’t fix it, the fastest way to stop guessing is to run SSH in verbose mode:
ssh -vT git@github.com
If that’s not enough:
ssh -vvT git@github.com
# or
ssh -vvvT git@github.com
What to look for:
A) “Offering public key …” lines
You might see:
Offering public key: /Users/me/.ssh/id_ed25519
Offering public key: /Users/me/.ssh/id_rsa
If you see no “Offering public key” lines, your client is not finding keys or is configured not to use them.
B) “Server accepts key” vs rejection
Good sign:
Server accepts key: /Users/me/.ssh/id_ed25519
Authenticated to github.com ([IP]:22).
Bad sign:
Offering public key: /Users/me/.ssh/id_ed25519
Authentiations that can continue: publickey
Permission denied (publickey).
That means GitHub/GitLab/Bitbucket didn’t accept that public key (not registered, wrong account, or connecting to different host than you think).
4) Fix: Your remote URL points to the wrong place
A very common cause: your remote is git@github.com:... but your company uses github.company.com, or you meant git@gitlab.company.com.
Check:
git remote -v
If needed, set the correct remote:
git remote set-url origin git@github.company.com:OWNER/REPO.git
Then test:
ssh -T git@github.company.com
If your company uses a non-standard port (example 2222), you can’t put that directly in the git@host:path scp-like syntax. Use an SSH config (see later) or a full SSH URL:
git remote set-url origin ssh://git@github.company.com:2222/OWNER/REPO.git
5) Fix: You’re using the wrong SSH key (multiple keys problem)
If you have multiple keys (personal + work), SSH may offer the “wrong” one first, and the server may reject it. Some servers stop after a few tries.
See what keys are loaded in your agent
ssh-add -l
If it says:
The agent has no identities.→ no keys loaded.
Load the correct key:
ssh-add ~/.ssh/id_ed25519
If you have multiple keys and want to start clean:
ssh-add -D
ssh-add ~/.ssh/work_id_ed25519
Force a specific key for a host via ~/.ssh/config
Edit (or create) ~/.ssh/config:
nano ~/.ssh/config
Example for GitHub with a specific key:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Now test:
ssh -T git@github.com
Why IdentitiesOnly yes matters:
Without it, SSH may offer many keys from your agent and from default paths. With it, SSH will only use the IdentityFile you specify (and any explicitly added identities), reducing “wrong key” failures.
Use two GitHub accounts (personal + work)
Create a host alias:
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/work_id_ed25519
IdentitiesOnly yes
Then set your repo remote to the alias:
git remote set-url origin git@github-work:OWNER/REPO.git
Test:
ssh -T git@github-work
6) Fix: Key exists but was never added to the Git provider
You can have a perfectly valid key locally, but if the public key is not registered on the server, it will always fail.
Confirm what your public key is
cat ~/.ssh/id_ed25519.pub
It should look like:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... your_email@example.com
Add that exact public key text to your Git host.
Common mistake: copying the private key instead of the public key
- Public key ends with
.pub - Private key has no extension and must never be shared
If you accidentally pasted the private key into a website, rotate it immediately:
- Delete the compromised key from the provider.
- Generate a new key pair.
- Update your SSH config and agent.
7) Fix: File permissions are wrong (SSH refuses to use your key)
SSH is strict about permissions. If your private key is readable by others, SSH may ignore it.
Run:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
If you use RSA:
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
Then retry:
ssh -T git@github.com
What this does and why it matters
~/.sshshould be accessible only to you.- Private keys must not be group/world readable.
- Public keys are fine to be readable.
If permissions are wrong, debug output often includes hints like:
Bad permissions: ignore key: /home/me/.ssh/id_ed25519
8) Fix: Your SSH agent isn’t running, or Git can’t prompt for passphrase
If your key is passphrase-protected and Git/SSH can’t prompt you (common in GUI apps, CI, or misconfigured terminals), authentication fails.
Ensure agent is running and key is added
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
macOS: store passphrase in Keychain
Add to ~/.ssh/config:
Host github.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
Then:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Linux desktop: use ssh-askpass if no TTY
In some environments, ssh needs an askpass helper. In CI, prefer deploying a key without passphrase (or use an SSH agent and secret storage). On a desktop, ensure you’re running in a terminal that can prompt, or configure an askpass program.
9) Fix: You’re using the wrong “git” username
For most Git hosting providers, the SSH username is literally git, not your account name.
Correct:
ssh -T git@github.com
Incorrect:
ssh -T yourname@github.com
In Git remotes, correct SSH format is:
git@github.com:OWNER/REPO.git
If you see a remote like yourname@github.com:OWNER/REPO.git, fix it:
git remote set-url origin git@github.com:OWNER/REPO.git
10) Fix: Your key type is not accepted (RSA/SHA1 issues)
Some servers or security policies reject older RSA keys or RSA signatures using SHA-1.
Prefer Ed25519
Generate:
ssh-keygen -t ed25519 -C "your_email@example.com"
Add it:
ssh-add ~/.ssh/id_ed25519
Register id_ed25519.pub with your provider, then test.
If you must use RSA, use a strong key
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
But Ed25519 is simpler and widely supported.
11) Fix: You’re behind a firewall / port 22 blocked
Some networks block outbound SSH (port 22). The symptom can vary, but you may see timeouts or inability to connect. Sometimes you still get auth-like errors depending on proxies.
Test connectivity
ssh -T git@github.com
If it hangs, try:
ssh -Tv git@github.com
If port 22 is blocked, GitHub supports SSH over port 443 using ssh.github.com.
Add to ~/.ssh/config:
Host github.com
HostName ssh.github.com
Port 443
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Then test:
ssh -T git@github.com
For GitLab/self-hosted services, check if they provide an alternate SSH port or allow HTTPS instead.
12) Fix: You cloned via HTTPS but think you’re using SSH (or vice versa)
If you want to use SSH, convert the remote:
git remote set-url origin git@github.com:OWNER/REPO.git
If you want to avoid SSH entirely, switch to HTTPS:
git remote set-url origin https://github.com/OWNER/REPO.git
Note: HTTPS now typically requires a Personal Access Token (PAT) instead of a password.
13) Fix: Repo access vs SSH authentication (they are different)
You can authenticate to the host but still not have access to a specific repository.
Distinguish the two
- Test host authentication:
ssh -T git@github.com
- Test repo access by listing refs:
git ls-remote origin
If SSH auth succeeds but git ls-remote fails, you likely have:
- No permission to that repo
- Wrong repo path (typo in
OWNER/REPO) - Repo is private and your account lacks access
- You are authenticating as a different account than you think (multi-key issue)
14) Common debug patterns and what they mean
Pattern A: “No such file or directory” for key
Example:
identity file /Users/me/.ssh/id_ed25519 type -1
Fix: create the key or point SSH to the correct path in ~/.ssh/config.
Pattern B: “Bad permissions”
Example:
Bad permissions: ignore key: /home/me/.ssh/id_rsa
Fix:
chmod 600 ~/.ssh/id_rsa
chmod 700 ~/.ssh
Pattern C: “Too many authentication failures”
This happens when SSH offers many keys and the server disconnects before it reaches the right one.
Fix: restrict identities:
Host github.com
IdentitiesOnly yes
IdentityFile ~/.ssh/id_ed25519
Optionally clear agent keys and add only one:
ssh-add -D
ssh-add ~/.ssh/id_ed25519
Pattern D: Works in terminal, fails in IDE (VS Code, JetBrains, Sourcetree)
Often the IDE uses a different SSH implementation or environment.
Fixes:
- Ensure the IDE is configured to use system OpenSSH.
- Ensure the agent is running in your login session.
- On macOS, ensure Keychain integration (
UseKeychain yes). - In JetBrains: Settings → Version Control → Git → SSH executable: “Native”.
15) A reliable “known-good” setup (recommended)
If you want a setup that works on most machines:
- Generate Ed25519 key:
ssh-keygen -t ed25519 -C "your_email@example.com"
- Add to agent:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
- Create
~/.ssh/config:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
- Add public key to provider, then test:
ssh -T git@github.com
- Ensure your remote is SSH:
git remote set-url origin git@github.com:OWNER/REPO.git
- Try:
git fetch
16) Safety notes (avoid common security mistakes)
- Never paste your private key (
~/.ssh/id_ed25519) into websites, chat, or tickets. - Use a passphrase for your key when possible, especially on laptops.
- If a key may have leaked, revoke it on the Git provider and generate a new one.
- Prefer per-device keys (one key per machine) so you can revoke a single device if lost.
17) Quick reference: fastest commands to run when you see the error
Run these in order and inspect output:
git remote -v
ls -al ~/.ssh
ssh-add -l
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh -vT git@github.com
Then fix based on what you see:
- No key files →
ssh-keygen - Agent has no identities →
ssh-add - Wrong host →
git remote set-url - Wrong key offered →
~/.ssh/configwithIdentitiesOnly yes - Key not registered → add
.pubto provider - Bad permissions →
chmod
18) If you’re still stuck: provide the right evidence
To troubleshoot efficiently, capture:
- Remote URL:
git remote -v
- SSH debug (redact usernames/emails if needed, but keep the “Offering public key” lines):
ssh -vvT git@github.com
- Agent keys list:
ssh-add -l
With those three, you can almost always pinpoint the exact failure: wrong host, wrong key, key not added, permissions, or blocked port.
Summary
“Permission denied (publickey)” is not a Git bug; it’s SSH telling you: the server didn’t accept any key you offered. The fastest fix is:
- Ensure you have a key (
ssh-keygen -t ed25519) - Load it (
ssh-add) - Register the public key on your Git provider
- Test with
ssh -T - If multiple keys exist, force the correct one via
~/.ssh/config
Follow the debug-driven approach above and you’ll solve it quickly—and understand why it broke in the first place.