← Back to Tutorials

Fix Git “Permission Denied (publickey)” Error in 3 Minutes

gitsshpublickeypermission-deniedgithubgitlabdevopstroubleshooting

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:

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:

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:

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:

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:

  1. Your client offers one or more public keys.
  2. The server checks if any offered public key is registered/authorized for that account.
  3. If it recognizes a key, it sends a challenge.
  4. Your client proves it has the matching private key by signing the challenge.
  5. Server grants access.

The error appears when:


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:

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

If you accidentally pasted the private key into a website, rotate it immediately:

  1. Delete the compromised key from the provider.
  2. Generate a new key pair.
  3. 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

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

  1. Test host authentication:
ssh -T git@github.com
  1. Test repo access by listing refs:
git ls-remote origin

If SSH auth succeeds but git ls-remote fails, you likely have:


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:


If you want a setup that works on most machines:

  1. Generate Ed25519 key:
ssh-keygen -t ed25519 -C "your_email@example.com"
  1. Add to agent:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
  1. Create ~/.ssh/config:
Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519
  IdentitiesOnly yes
  1. Add public key to provider, then test:
ssh -T git@github.com
  1. Ensure your remote is SSH:
git remote set-url origin git@github.com:OWNER/REPO.git
  1. Try:
git fetch

16) Safety notes (avoid common security mistakes)


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:


18) If you’re still stuck: provide the right evidence

To troubleshoot efficiently, capture:

  1. Remote URL:
git remote -v
  1. SSH debug (redact usernames/emails if needed, but keep the “Offering public key” lines):
ssh -vvT git@github.com
  1. 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:

  1. Ensure you have a key (ssh-keygen -t ed25519)
  2. Load it (ssh-add)
  3. Register the public key on your Git provider
  4. Test with ssh -T
  5. 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.