TechEarl

Git: 'Permission denied (publickey)' - How to Fix It

The 'Permission denied (publickey)' error means SSH could not prove who you are to GitHub. Here is the ordered checklist that fixes it: key, agent, GitHub, test.

Ishan Karunaratne⏱️ 8 min readUpdated
Share thisCopied
Fixing the Git Permission denied publickey SSH authentication error with GitHub

Permission denied (publickey) means SSH could not prove to GitHub that you are who you say you are. GitHub asked for a key, your machine either had none to offer or offered one GitHub does not recognize, so the connection was refused. The fix is to make sure you have an SSH key, that it is loaded into your SSH agent, and that its public half is attached to your GitHub account.

Here is the full error you are probably staring at:

text
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.

Despite the second paragraph, this is almost never about access rights or a missing repository. It is an SSH authentication failure, full stop. Work the checklist below in order and you will land on the broken step.

Why this happens

When your remote URL starts with git@github.com:, Git talks to GitHub over SSH. SSH authenticates you with a key pair: a private key that stays on your machine and a public key you give to GitHub. GitHub never asks for a password on an SSH remote. It only checks: "does this person hold a private key whose public half I have on file?" If the answer is no, you get Permission denied (publickey).

So there are exactly three things that can be wrong, and they map to three checks:

  1. You do not have an SSH key.
  2. You have a key, but your SSH agent is not offering it.
  3. You have a key and the agent is offering it, but GitHub does not have the matching public key on your account.

If you are not even sure you want SSH here, the SSH vs HTTPS remotes comparison lays out the trade-off; switching to an HTTPS remote sidesteps this error entirely. But if you are committed to SSH, keep reading.

Step 1: Do you have an SSH key?

Check what is in your .ssh directory:

bash
ls -al ~/.ssh

You are looking for a pair like id_ed25519 (private) and id_ed25519.pub (public), or the older id_rsa / id_rsa.pub. If you see them, skip to Step 2. If the directory does not exist or is empty, you have no key, and that is your problem. Generate one:

bash
ssh-keygen -t ed25519 -C "your_email@example.com"

Press Enter to accept the default file location. Set a passphrase if you want one (recommended). This writes ~/.ssh/id_ed25519 and ~/.ssh/id_ed25519.pub. If you want the full cross-platform walkthrough, including the Windows and macOS specifics, I cover how to create an SSH key from scratch in its own guide.

One mistake worth naming: do not run ssh-keygen with sudo. That writes a root-owned key into /root/.ssh that your normal user cannot read, and you will keep hitting the same error wondering why a key you "just made" does nothing. Generating your own key is a user-scoped task. No sudo.

If ssh-keygen is not found, install OpenSSH (it ships by default on macOS and most Linux; on Windows use Git Bash, which bundles it).

Step 2: Is the key loaded into the agent?

The SSH agent holds your private key in memory so SSH can offer it without prompting for the passphrase every time. Start the agent and add your key:

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

Confirm the key is loaded:

bash
ssh-add -l

That lists the fingerprints the agent currently holds. If it prints The agent has no identities, your key is not loaded and SSH has nothing to offer GitHub, which produces the exact error you are seeing. Re-run the ssh-add line above.

On macOS, you usually want the agent to load the key automatically and pull the passphrase from the Keychain. Add this to ~/.ssh/config:

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

Then add it to the Keychain once:

bash
ssh-add --apple-use-keychain ~/.ssh/id_ed25519   # macOS Monterey (12) and later
# On older macOS (before 12) use the short form:
ssh-add -K ~/.ssh/id_ed25519

Step 3: Is the public key on your GitHub account?

This is the step people skip, and it is the most common cause. Having a key locally does nothing if GitHub has never seen the public half. Print your public key:

bash
cat ~/.ssh/id_ed25519.pub

Copy the entire line (it starts with ssh-ed25519 and ends with your email comment). Then in GitHub: Settings, SSH and GPG keys, New SSH key. Paste it, give it a title, and save. I wrote a step-by-step walkthrough of exactly this part with screenshots in how to add an SSH key to GitHub; use it if the GitHub UI bit is where you are stuck.

A subtle trap: if you have several keys, make sure the public key you paste into GitHub matches the private key the agent is offering. Mismatched pairs fail silently with the same Permission denied (publickey) message.

GitLab works the same way: the same .pub file goes into its Settings, SSH Keys panel, and the test command becomes ssh -T git@gitlab.com.

Step 4: Test the connection

Once the key exists, is loaded, and is on GitHub, verify the whole chain with GitHub's test endpoint:

bash
ssh -T git@github.com

A working setup answers like this:

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

That "does not provide shell access" line is the success message, not an error: GitHub deliberately does not give you a shell. Seeing your username there means authentication works and your git push and git pull over SSH will go through. If you instead get Permission denied (publickey) from this command too, you have isolated the problem to SSH itself (not Git), and one of Steps 1 to 3 is still wrong.

Reading the verbose output

If the test still fails after the checklist, ask SSH to narrate what it is doing:

bash
ssh -vT git@github.com

Two lines tell you most of the story. Watch for the key SSH actually offers:

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

If you see Offering public key followed by GitHub continuing to ask for publickey, the key being offered is not the one on your account: back to Step 3. If you see no Offering public key line at all, the agent is empty or pointing at a missing file: back to Step 2.

Quick reference

SymptomWhat it meansFix
~/.ssh is emptyNo key existsssh-keygen -t ed25519 (Step 1)
ssh-add -l says no identitiesKey not loaded in agentssh-add ~/.ssh/id_ed25519 (Step 2)
Key offered, GitHub still refusesPublic key not on account, or wrong keyAdd the matching .pub to GitHub (Step 3)
ssh -T works, git push failsRemote is HTTPS, not SSHSwitch the remote URL to git@github.com:...

When the wrong remote is the real cause

If ssh -T git@github.com greets you by name but git push still throws the error, your remote is not actually using SSH. Check it:

bash
git remote -v

An HTTPS remote looks like https://github.com/user/repo.git. To use the SSH key you just set up, switch it:

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

If there is no remote at all yet, git remote -v prints nothing; in that case you have not wired up the remote, and the path to fix it is to add Git to a project and wire up the remote before any of this SSH troubleshooting applies.

This is also worth knowing because GitHub removed password authentication for HTTPS years ago, which trips people up in a different way; I cover that in the password authentication removed fix. The two errors look unrelated but both come down to "how are you proving who you are."

Where this sits in the bigger picture

Getting SSH working is part of the foundation for everything else: cloning, pushing to a branch with no upstream, and opening your first pull request. If you are early in your Git journey, the Git for beginners guide is the hub that ties these pieces together and points to the rest of the series.

Sources

Authoritative references this article was fact-checked against.

Tagsgit permission denied publickeyGitVersion ControlSSHGitHub

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

Fix SSH "Permission denied (publickey)"

The ordered checklist for SSH Permission denied (publickey): is the key loaded, is it the right key, is the public half on the server, and are the server-side permissions sane.