Git Permission Denied (publickey) Error Explained + Fix in 5 Minutes

By Kedar Salunkhe | Last Updated March 2026

You typed git push. You expected your code to fly up to GitHub. Instead, you got this:

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.

And now you’re here, probably a little frustrated, wondering what you did wrong.

Here’s the honest truth — you probably didn’t do anything wrong. This error catches developers at every level, from someone pushing their first project to a senior engineer setting up a fresh machine. It looks alarming, but it has a handful of well-known causes and every single one of them is completely fixable.

By the time you finish reading this guide, you’ll understand exactly what’s happening under the hood, know how to diagnose which specific cause applies to your situation, have the exact commands to fix it, and know how to make sure it never happens again.

Let’s get into it.


Git Permission Denied — The Full Guide

Git Permission Denied  — The Full Guide

What Is This Error?

The full error message reads:

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.

You may also see variations depending on your OS, Git version, or which platform you’re using:

Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

ssh: connect to host github.com port 22: Connection refused

Warning: Permanently added 'github.com' (RSA) to the list of known hosts.
git@github.com: Permission denied (publickey).

All of these point to the same underlying issue. It’s an SSH authentication failure. Git tried to prove your machine’s identity to GitHub, and GitHub said no.

Before we fix it, it helps to understand why SSH keys exist in the first place — because once you understand the system, the fix becomes obvious.


Why Does Git Use SSH Keys at All?

When you interact with a remote repository on GitHub, GitLab, or Bitbucket, your computer needs to prove that you’re allowed to access it. There are two ways Git can do this: HTTPS (username and password, or a personal access token) and SSH (a cryptographic key pair).

SSH is the preferred method for most developers because it’s more secure, doesn’t require you to type a password on every push, and works seamlessly in automated environments like CI/CD pipelines.

SSH authentication works on a public-key cryptography model. Here’s how it works in plain English:

You generate a key pair on your local machine. This gives you two files — a private key (which stays on your machine and is never shared with anyone) and a public key (which you can hand out freely).

You paste the public key into your GitHub account settings.

When you run git push, SSH takes your private key and uses it to create a cryptographic signature. GitHub checks that signature against the public key you uploaded. If they match, access is granted. If they don’t, or if no matching key is found at all, you get “Permission denied (publickey).”

That’s the whole system. The error simply means: GitHub checked its records, found no matching public key for your machine, and refused the connection.

Now let’s look at exactly why that matching fails.


Why This Happens — The Root Causes

Why This Happens — The Root Causes

There are four common reasons you’ll see this error. Understanding which one applies to you is the key to picking the right fix.

Cause 1 — No SSH Key Exists on Your Machine

The most common scenario, especially for new developers or anyone setting up a fresh machine. If you’ve never run ssh-keygen, there’s no key to present. SSH has nothing to offer GitHub, and the connection fails immediately.

This also happens after a clean OS reinstall, switching to a new laptop, or wiping your home directory. Your old key is gone, and GitHub is still looking for it.

Cause 2 — The Public Key Was Never Added to GitHub

You generated a key pair at some point, but you skipped the step where you paste the public key into your GitHub settings. Your machine has the private key, but GitHub has no corresponding public key to match against.

This is surprisingly common. Developers often generate the key, get distracted, and forget to complete the registration step.

Cause 3 — The SSH Agent Isn’t Running or Has Forgotten Your Key

The SSH agent is a background process that holds your decrypted private key in memory so you don’t have to re-enter your passphrase every single time you push. If you set a passphrase on your key (which is good practice), the agent needs to be running and have your key loaded.

After a system reboot, a new terminal session, or a logout, the agent often starts fresh with no keys loaded. Everything looks fine on the surface — the key files exist, they’re registered on GitHub — but the agent isn’t presenting them, so the connection fails.

Cause 4 — The Remote URL Uses HTTPS Instead of SSH

This one trips up a lot of people because it looks like an SSH problem when it isn’t. If your repository’s remote URL starts with https://, Git will use HTTPS authentication, not SSH. Your SSH keys are completely irrelevant in this case.

The fix here isn’t about SSH keys at all — it’s about updating the remote URL.

You can quickly check which cause applies by running:

ssh -T git@github.com

If it returns “Hi username! You’ve successfully authenticated, but GitHub does not provide shell access.” — your SSH setup is perfectly fine and you likely have Cause 4. If it returns “Permission denied (publickey),” you have Cause 1, 2, or 3.


Step-by-Step Fix

Step 1 — Check If an SSH Key Already Exists

Before generating anything new, check what’s already on your machine:

ls -al ~/.ssh

You’re looking for pairs of files like:

id_ed25519 and id_ed25519.pub
id_rsa and id_rsa.pub
id_ecdsa and id_ecdsa.pub

The .pub file is your public key. The file without the extension is your private key. If you see these files, skip ahead to Step 3. If the ~/.ssh directory is empty, doesn’t exist, or you only see config and known_hosts with no key files, continue to Step 2.

Step 2 — Generate a New SSH Key Pair

Use the Ed25519 algorithm. It’s the current standard — shorter, faster, and more secure than the older RSA approach. Replace the email address below with the one attached to your GitHub account:

ssh-keygen -t ed25519 -C “you@example.com”

You’ll see a few prompts:

Enter file in which to save the key (/home/user/.ssh/id_ed25519):

Press Enter to accept the default location unless you have a specific reason to put it elsewhere.

Enter passphrase (empty for no passphrase):

This is optional but strongly recommended. A passphrase encrypts your private key so that even if someone gets access to the file, they can’t use it without knowing the passphrase. We’ll show you how to avoid typing it on every push in the prevention section.

After completing this, you’ll have two new files: ~/.ssh/id_ed25519 (your private key — treat this like a password, never share it or commit it) and ~/.ssh/id_ed25519.pub (your public key — safe to share and what you’ll give to GitHub).

If you’re on an older system that doesn’t support Ed25519, use RSA instead:

ssh-keygen -t rsa -b 4096 -C "you@example.com"

Step 3 — Start the SSH Agent and Load Your Key

The SSH agent needs to be running and aware of your key before SSH can use it. This is the step most guides skip, and it’s often the sole reason for the error even when keys exist.

On macOS and Linux:

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

On Windows using Git Bash:

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

If you set a passphrase in Step 2, you’ll be prompted to enter it here. After this, the agent holds your decrypted key in memory for the current session.

You should see output like:

Agent pid 12345
Identity added: /home/user/.ssh/id_ed25519 (you@example.com)

Step 4 — Copy Your Public Key to Your Clipboard

You need to paste the contents of the public key file into GitHub. Do not open and copy the private key by mistake — always use the .pub file.

On macOS:

pbcopy < ~/.ssh/id_ed25519.pub

On Linux (requires xclip):

xclip -sel clip < ~/.ssh/id_ed25519.pub

If xclip isn’t installed, just print the key and copy it manually:

cat ~/.ssh/id_ed25519.pub

On Windows (Git Bash):

clip < ~/.ssh/id_ed25519.pub

The public key is a single long line of text that starts with ssh-ed25519 (or ssh-rsa for RSA keys) followed by a string of characters, and ending with your email address. Make sure you copy the entire line including the email at the end.

Step 5 — Add the Public Key to GitHub

Log in to GitHub and go to Settings. In the left sidebar, click SSH and GPG keys, then click the New SSH key button.

Give the key a title that helps you identify which machine it belongs to. Something like “Personal MacBook 2025” or “Work Ubuntu Laptop” is much more useful than a generic name, especially if you use multiple machines.

Paste the public key you copied into the Key field and click Add SSH key. GitHub may ask for your password to confirm.

For GitLab users: go to User Settings → SSH Keys.
For Bitbucket users: go to Personal settings → SSH keys.

The process is identical across all three platforms.

Step 6 — Test the Connection

Always verify before going back to git push:

ssh -T git@github.com

The first time you connect to GitHub from a new machine, you may see:

The authenticity of host 'github.com (IP)' can't be established.
RSA key fingerprint is SHA256:xxxx.
Are you sure you want to continue connecting (yes/no)?

Type yes and press Enter. SSH will add GitHub to your known_hosts file so this prompt doesn’t appear again.

After confirming, you should see:

Hi yourusername! You’ve successfully authenticated, but GitHub does not provide shell access.

That message is correct and expected. GitHub intentionally doesn’t give shell access over SSH — it only uses SSH for Git operations. The “but GitHub does not provide shell access” part is just informational, not an error.

If you see this message, your SSH setup is working. Run git push again and it’ll go through.

Step 7 — Fix a Wrong Remote URL (If Needed)

If ssh -T git@github.com passes but git push still fails, check whether your repository’s remote URL is using HTTPS instead of SSH:

git remote -v

If the output shows something like:

origin https://github.com/USERNAME/REPO.git (fetch)
origin https://github.com/USERNAME/REPO.git (push)

Switch it to SSH:

git remote set-url origin git@github.com:USERNAME/REPO.git

Then try git push again.


Real Terminal Example — From Scratch to Working Push

Here’s a complete session showing every command and every response, exactly as it appears in the terminal on a fresh Ubuntu machine:

$ ls -al ~/.ssh
ls: cannot access ‘/home/user/.ssh’: No such file or directory

$ ssh-keygen -t ed25519 -C "dev@example.com"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519):
Created directory '/home/user/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:abc123xyz dev@example.com
The key's randomart image is:
+--[ED25519 256]--+
| .o+o. |
+----[SHA256]-----+
$ eval "$(ssh-agent -s)"
Agent pid 23456
$ ssh-add ~/.ssh/id_ed25519
Enter passphrase for /home/user/.ssh/id_ed25519:
Identity added: /home/user/.ssh/id_ed25519 (dev@example.com)
$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI… dev@example.com

[copied this output and pasted into GitHub settings]

$ ssh -T git@github.com
The authenticity of host 'github.com (140.82.121.4)' can't be established.
ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'github.com' (ED25519) to the list of known hosts.
Hi devuser! You've successfully authenticated, but GitHub does not provide shell access.
$ git push origin main
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 312 bytes | 312.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
To github.com:devuser/my-project.git
a1b2c3d..e4f5g6h main -> main

Prevention Tips — How to Make Sure This Never Happens Again

Prevention Tips — How to Make Sure This Never Happens Again

Fixing the error once is good. Never having to fix it again is better. Here’s how to set yourself up so this error stays gone.

Tip 1 — Set Up Your SSH Config File

This is the single most useful thing you can do after fixing the error. Create or edit the file at ~/.ssh/config and add the following:

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

What this does: AddKeysToAgent yes tells SSH to automatically load your key into the agent whenever it’s needed. IdentityFile tells SSH exactly which key to use for GitHub connections. On macOS, you can also add UseKeychain yes to store the passphrase in your system Keychain so you never have to type it again.

macOS version:

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

After saving this file, you’ll never need to manually run ssh-add again.

Tip 2 — Always Clone Using SSH URLs

The habit that prevents Cause 4 entirely. When you copy a clone URL on GitHub, there’s a small dropdown that lets you switch between HTTPS, SSH, and GitHub CLI. Always choose SSH.

SSH URLs look like this:
git@github.com:username/repository.git

HTTPS URLs look like this:
https://github.com/username/repository.git

If you’ve already cloned a repo with HTTPS and want to switch it to SSH, use this command:

git remote set-url origin git@github.com:USERNAME/REPO.git

Tip 3 — Back Up Your SSH Keys Securely

Your private key lives in ~/.ssh/id_ed25519. If you wipe your machine, reinstall your OS, or lose your laptop without a backup, that key is gone. You’d need to generate a new one and re-register it on GitHub.

Store a copy of your private key in a password manager that supports file attachments (like 1Password or Bitwarden) or in an encrypted archive. Treat it with the same care as a password — never store it in plain text in a cloud folder, and never commit it to a repository.

Tip 4 — Use a Passphrase on Your Private Key

A passphrase-protected key means that even if someone copies the file off your machine, they can’t use it without also knowing the passphrase. Combined with the SSH config Keychain setup on macOS, the security comes at essentially zero convenience cost — you set it once and macOS handles the rest.

Tip 5 — Add the SSH Key to GitHub Before You Start Working

When you set up a new machine, make the SSH key the very first thing you configure before cloning any repositories. Five minutes upfront saves you from hitting this error mid-workflow when you’re trying to focus on something else.

Tip 6 — Name Your SSH Keys Clearly on GitHub

Go to GitHub → Settings → SSH and GPG keys and make sure every key has a descriptive name and a mental note of which machine it lives on. When you retire a machine, delete its key from GitHub. A cluttered list of unnamed keys from machines you no longer own is a security risk and a diagnostic headache.


FAQ

Q: Why do I get this error even though I set up SSH before?

The most common reason is that your SSH agent lost the key after a reboot or a new terminal session. The key file still exists on disk, but the agent isn’t presenting it to GitHub. Run eval “$(ssh-agent -s)” followed by ssh-add ~/.ssh/id_ed25519 to reload it. If you set up the ~/.ssh/config file with AddKeysToAgent yes, this happens automatically and you won’t need to think about it again.

Q: Does this error mean my GitHub password is wrong?

No. SSH key authentication is completely separate from your GitHub account password. The error is about whether your machine’s private key matches a public key registered in your GitHub SSH settings. Your password is not involved at all when using SSH.

Q: I generated a key and added it to GitHub, but I’m still getting the error. What now?

Start by running ssh -vvv git@github.com. The triple -v flag turns on ultra-verbose output and will show you exactly which key files SSH tried to use, whether it contacted the agent, and at which point the connection failed. Read through it carefully — the answer is almost always in there.

Q: Can I use the same SSH key on multiple machines?

Technically yes, but it’s not recommended. The better approach is to generate a separate key on each machine and register all of them on GitHub. That way, if one machine is compromised or retired, you can revoke just that key without affecting your other machines. GitHub allows you to register as many SSH keys as you need.

Q: Can I use the same SSH key for GitHub and GitLab?

You can paste the same public key into both platforms, and it will work. However, if you want to use different keys per platform (for access control or security reasons), add separate Host blocks in your ~/.ssh/config file for each:

Host github.com
IdentityFile ~/.ssh/id_ed25519_github

Host gitlab.com
IdentityFile ~/.ssh/id_ed25519_gitlab

Q: What’s the difference between id_rsa and id_ed25519?

Both are SSH key types. id_rsa uses the RSA algorithm, which has been the standard for decades and is typically generated at 2048 or 4096 bits. id_ed25519 uses the Ed25519 algorithm, which was introduced more recently. Ed25519 keys are shorter, faster to generate, faster to use during authentication, and considered more secure than equivalent-length RSA keys. If you’re generating a new key today, always use Ed25519. If you have an existing id_rsa key that’s already registered on GitHub and working, there’s no urgent need to replace it.

Q: The ssh -T test works but git push still fails. Why?

This usually means one of two things. Either your remote URL is using HTTPS instead of SSH (run git remote -v to check and use git remote set-url to fix it), or you’re pushing to a repository you don’t have write access to. The first scenario is more common. Check the remote URL first.

Q: My company network blocks port 22. Is there a workaround?

Yes. GitHub supports SSH over port 443, which is the standard HTTPS port and almost never blocked by corporate firewalls. Add this to your ~/.ssh/config:

Host github.com
Hostname ssh.github.com
Port 443
User git
IdentityFile ~/.ssh/id_ed25519

Run ssh -T git@github.com again after saving this — it’ll connect through port 443 instead of 22.

Q: I see “WARNING: UNPROTECTED PRIVATE KEY FILE” — what does that mean?

It means the file permissions on your private key are too open. SSH will refuse to use a private key that other users on the system can read. Fix it with:

chmod 600 ~/.ssh/id_ed25519
chmod 700 ~/.ssh

This sets the private key to owner-read-only and the .ssh directory to owner-only access, which is what SSH requires.

Q: Should I use SSH or HTTPS for GitHub?

Both work. HTTPS is simpler to set up initially and is the default when you copy a clone URL from GitHub. SSH requires a one-time setup but is more convenient long term — no passwords or tokens to manage, and it works seamlessly in scripts and automation. If you work with Git regularly, the SSH setup is worth doing once and forgetting about.


Related Errors

These are the errors you’re most likely to encounter alongside or after fixing the publickey error.

Host key verification failed

This happens when GitHub’s host fingerprint doesn’t match what’s stored in your ~/.ssh/known_hosts file. It typically occurs after GitHub rotates its host keys (which happened in March 2023) or when connecting from a machine that has never reached GitHub before.

Fix:

ssh-keyscan github.com >> ~/.ssh/known_hosts

This fetches GitHub’s current host key and adds it to your known_hosts file.

fatal: Authentication failed (HTTPS)

A different error that looks similar. This happens with HTTPS remotes when your stored credentials (username/password or personal access token) are expired or incorrect. It has nothing to do with SSH keys. Fix it by updating your credentials in your OS credential manager, or switch the remote URL to SSH.

ERROR: Repository not found

SSH authentication succeeded (your key worked), but you’re authenticated as the wrong GitHub account. This happens when you have multiple GitHub accounts and the wrong SSH key is being used. Verify with ssh -T git@github.com to see which GitHub username your current key resolves to.

sign_and_send_pubkey: signing failed: agent refused operation

The SSH agent is running but refused to sign with the key. This usually means the key was added to the agent without the passphrase, or the key file has permission issues. Run ssh-add -l to list loaded keys. If it shows “The agent has no identities,” reload with ssh-add ~/.ssh/id_ed25519.

WARNING: UNPROTECTED PRIVATE KEY FILE

SSH won’t use a private key file that other users on the system can read. Fix the permissions:

chmod 600 ~/.ssh/id_ed25519

ssh: connect to host github.com port 22: Connection refused

The connection to port 22 was blocked. This is a network restriction, not a key problem. Use the port 443 workaround covered in the FAQ section above.


Conclusion

The “Permission denied (publickey)” error is one of those things that sounds more serious than it actually is. At its core, it’s a simple mismatch: GitHub is looking for a public key that either doesn’t exist in its records, or your machine isn’t presenting correctly.

The fix almost always comes down to four steps: generate a key if you don’t have one, add it to GitHub if it’s not already there, make sure the SSH agent is running and has the key loaded, and confirm your remote URL is using SSH rather than HTTPS.

The part that pays dividends long-term is the prevention setup. Taking five extra minutes to configure the ~/.ssh/config file with AddKeysToAgent yes means you’ll never have to manually reload your key again. Cloning with SSH URLs from the start means you’ll never hit the HTTPS mismatch. Backing up your private key means a new machine is a 10-minute setup rather than a full re-registration exercise.

If you’re still seeing the error after following all of these steps, ssh -vvv git@github.com is your best friend. The verbose output is detailed, but it tells you exactly which keys were tried, which config was loaded, and where the handshake broke down. Paste the output into a search engine or a support forum and you’ll have an answer within minutes.

SSH authentication is one of those things that feels complicated until it suddenly doesn’t. Once it’s working and properly configured, it just quietly does its job in the background — and you’ll forget this error ever existed.


Related Resources

GitHub Official Docs — Connecting to GitHub with SSH

GitHub Official Docs — Testing your SSH connection

GitHub Blogs – Collection of git related articles on this website


About the Author

Kedar Salunkhe

DevOps Engineer | Seven years of fixing things that break at 2am
Kubernetes • OpenShift • AWS • Coffee

I’ve spent almost 7 years keeping production systems running, often when everyone else is asleep. These days I’m working with Kubernetes and OpenShift deployments, automating everything that can be automated, and occasionally remembering to document the things I fix. When I’m not troubleshooting clusters, I’m probably trying out new DevOps tools or explaining to someone why we can’t just “restart everything” as a debugging strategy. You can usually find me where the coffee is strong and the error logs are confusing.

Leave a Comment