Fix "git@github.com: Permission denied (publickey)"

git@github.com: Permission denied (publickey). means GitHub's SSH server did not accept any key your computer offered, usually because no key was loaded or the key isn't added to your GitHub account. Run ssh -T git@github.com to test the connection on its own, then fix whichever step fails below, or switch the remote to HTTPS.

What the error looks like

From a git push, git pull or git clone over SSH:

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.

The first line comes from SSH, the rest from Git. Git's lines are generic; the SSH line is the one that tells you authentication failed before Git could even ask about the repository.

Step 1: test SSH on its own

ssh -T git@github.com

If your key works, GitHub replies:

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

If it doesn't, you get the same git@github.com: Permission denied (publickey). line, and ssh exits with status 255. The first time you connect, SSH also asks you to confirm GitHub's host key (The authenticity of host 'github.com (IP ADDRESS)' can't be established.); compare the fingerprint with the ones GitHub publishes before typing yes.

Always use the user git, as in git@github.com. GitHub's docs say every connection "must be made as the 'git' user"; your GitHub username goes nowhere in the SSH address.

Step 2: see which keys SSH tries

ssh -vT git@github.com

The verbose output is long. These are the lines that matter, from a real run on a machine with no keys (Git for Windows, OpenSSH 9.7):

debug1: identity file /c/Users/you/.ssh/id_rsa type -1
debug1: identity file /c/Users/you/.ssh/id_ed25519 type -1
debug1: Authenticating to github.com:22 as 'git'
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
git@github.com: Permission denied (publickey).

type -1 means SSH looked for that file and didn't find it. With a key present, you get an "Offering" line instead. This run used a freshly generated key that was not added to any GitHub account (key path shortened):

debug1: Offering public key: /c/Users/you/.ssh/id_ed25519 ED25519 SHA256:A1/VZqSknH4lHFH2dh4uawNYwg7Hsiysrt9JvGwS0vQ
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
git@github.com: Permission denied (publickey).

"Offering" followed by another "Authentications that can continue" means GitHub saw the key and rejected it: it is not on your account (Step 4). If no "Offering" line appears at all, SSH has no key to offer (Step 3). Also check the connection line: GitHub's docs say it should be port 22 unless you have deliberately configured SSH over HTTPS.

Step 3: make sure a key exists and the agent has it

List your key files:

ls ~/.ssh

You are looking for a pair such as id_ed25519 and id_ed25519.pub. If there is none, create one with the command from GitHub's docs, using your GitHub email address:

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

Then check what the SSH agent holds:

ssh-add -l -E sha256

If the agent isn't running, the reply is Could not open a connection to your authentication agent. Start it and add the key:

# macOS, Linux, and Git Bash on Windows
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

On macOS, GitHub's docs add --apple-use-keychain to ssh-add so the passphrase is stored in the keychain. On Windows with the built-in OpenSSH, start the agent service once from an administrator PowerShell:

Get-Service -Name ssh-agent | Set-Service -StartupType Manual
Start-Service ssh-agent

then run ssh-add c:/Users/YOU/.ssh/id_ed25519 in a normal terminal.

If your key has a non-default name, SSH won't try it automatically. Test it explicitly with ssh -i ~/.ssh/KEY-FILE -vT git@github.com, then add it to the agent or to ~/.ssh/config as an IdentityFile under Host github.com.

Step 4: check the key is on your GitHub account

Print your key's fingerprint:

ssh-add -l -E sha256

Or read it straight from the public key file, without the agent:

ssh-keygen -lf ~/.ssh/id_ed25519.pub

Example output (from the test key above):

256 SHA256:A1/VZqSknH4lHFH2dh4uawNYwg7Hsiysrt9JvGwS0vQ test@example.com (ED25519)

On GitHub, go to Settings, then SSH and GPG keys, and compare. If the fingerprint isn't listed, add the contents of the .pub file there (never the private file without .pub). If you have more than one GitHub account, make sure the key is on the account that has access to the repository. GitHub's docs add that if you see a key listed that you don't recognise, delete it and contact GitHub Support.

Don't use sudo

GitHub's docs are explicit: "You should not be using the sudo command or elevated privileges, such as administrator permissions, with Git." They explain that if you generated your key without sudo and then run sudo git push, you are not using the same key you generated.

Port 22 blocked: SSH over port 443

Some corporate and public networks block outgoing port 22. GitHub accepts SSH on port 443 at a different hostname. Test it:

ssh -T -p 443 git@ssh.github.com

If that works, make it permanent in ~/.ssh/config:

Host github.com
    Hostname ssh.github.com
    Port 443
    User git

A key that isn't on your account fails on port 443 with the same Permission denied (publickey), so this only helps when the connection itself was being blocked.

Switch between SSH and HTTPS remotes

Check which kind of URL your repository uses:

git remote -v

An SSH remote looks like git@github.com:OWNER/REPOSITORY.git; an HTTPS one like https://github.com/OWNER/REPOSITORY.git. This error only happens with SSH remotes. If you'd rather not deal with keys, switch to HTTPS:

git remote set-url origin https://github.com/OWNER/REPOSITORY.git

Or, once SSH works, switch the other way:

git remote set-url origin git@github.com:OWNER/REPOSITORY.git

Run git remote -v again to confirm.

If ssh -T works but git push still fails

Then your key is fine and the problem is elsewhere: a typo in the repository path in the remote URL, a repository you don't have write access to, or a key that belongs to a different GitHub account from the one with access. A separate push rejection that mentions non-fast-forward is not an authentication problem at all; see undoing and amending commits and merge vs rebase.

Frequently asked questions

Should I use sudo to fix Permission denied (publickey)?
No. GitHub's docs say not to use sudo or administrator rights with Git. If you generated your key without sudo, running git with sudo uses a different set of keys, so the key you set up is not the one offered.
What does 'Hi username! You've successfully authenticated, but GitHub does not provide shell access' mean?
It means your SSH key works. GitHub recognised the key and the account it belongs to; the second half only says you can't open a shell on GitHub's servers, which is expected. If git push still fails after this, the problem is repository access or the remote URL, not your key.
I added my key to GitHub but still get the error. Why?
Usually SSH is offering a different key than the one you added, or no key at all. Run ssh -vT git@github.com and check the 'Offering public key' lines, then compare the fingerprint from ssh-add -l -E sha256 with the one shown under Settings, SSH and GPG keys on GitHub.
Can I avoid SSH keys entirely?
Yes. Switch the remote to HTTPS with git remote set-url origin https://github.com/OWNER/REPOSITORY.git. Git then authenticates over HTTPS instead, and SSH keys are not involved.

Sources