Skip to content

Fix: Permission denied (publickey) – Git SSH Authentication Failed

FixDevs · (Updated: )

Part of:  Docker, DevOps & Infrastructure

Quick Answer

How to fix '[email protected]: Permission denied (publickey)' and 'fatal: Could not read from remote repository' when pushing or cloning over SSH. Covers key generation, ssh-agent, GitHub/GitLab setup, and edge cases.

The Error

You run git push, git pull, or git clone over SSH and get:

[email protected]: 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 just the first line:

Permission denied (publickey).

Or a variation when connecting to GitLab or Bitbucket:

[email protected]: Permission denied (publickey,keyboard-interactive).

Why This Happens

SSH authentication failed. Git tried to connect to the remote server over SSH, and the server rejected the connection because it could not verify your identity.

When you run git push over SSH, Git invokes the system ssh binary, which presents one of your private keys to the server. The server then checks whether the matching public key is registered on the account that owns the repository. If no key matches, or if your SSH client cannot find a key to offer, the server returns Permission denied (publickey). This single message covers a wide range of underlying causes, which is why the error is so common.

The check happens before Git is even involved. That is why ssh -T [email protected] reproduces the same failure: the problem is at the SSH layer, not in Git itself.

This happens when:

  • You don’t have an SSH key. You never generated one on this machine.
  • Your SSH key isn’t added to the ssh-agent. The key exists on disk but your SSH client isn’t using it.
  • Your public key isn’t added to GitHub/GitLab/Bitbucket. The server doesn’t know about your key.
  • You have the wrong key loaded. You have multiple keys and SSH is presenting one the server doesn’t recognize.
  • Your remote URL uses SSH but you intended HTTPS. The remote is set to [email protected]:... instead of https://github.com/....
  • You are using an old RSA key with SHA-1 signatures. GitHub stopped accepting RSA SHA-1 signatures in March 2022, and modern OpenSSH disables the algorithm by default.

A Note on SSH Key Algorithm History

The recommended key type for Git hosting has shifted over the years. Knowing the history helps you understand which fixes apply to your situation.

RSA keys have been the default for decades. Most older tutorials still tell you to run ssh-keygen -t rsa -b 4096. The keys still work, but the way they are signed has changed. OpenSSH 8.2 (released February 2020) introduced the rsa-sha2-256 and rsa-sha2-512 signature algorithms, and OpenSSH 8.7 (August 2021) disabled the legacy ssh-rsa (SHA-1) signature by default. If a server only accepts the legacy SHA-1 variant, your modern client refuses to sign with it, and you see Permission denied (publickey) even though both sides have your key.

GitHub went the other direction in March 2022. It stopped accepting ssh-rsa (SHA-1) signatures entirely after a brokered key exposure incident. The fix on GitHub’s side was to require rsa-sha2-256 or rsa-sha2-512. Most users were unaffected because their clients had already moved on. But if you are on Windows with an older OpenSSH bundle or on a long-lived Linux server, you may still hit this.

Ed25519 keys, introduced in OpenSSH 6.5 (2014), are smaller, faster, and use modern elliptic-curve cryptography. They have a single signature algorithm and avoid the SHA-1 problem entirely. GitHub, GitLab, Bitbucket, and Azure DevOps all support Ed25519. Unless you are on a very old system (RHEL 6, ancient embedded device), use Ed25519 — ssh-keygen -t ed25519 -C "[email protected]". New documentation has used Ed25519 as the default recommendation since 2022.

Fix 1: Check if You Have an SSH Key

First, check whether you already have an SSH key pair:

ls -la ~/.ssh

Look for a pair of files like:

  • id_ed25519 and id_ed25519.pub
  • id_rsa and id_rsa.pub

The .pub file is your public key (the one you give to GitHub). The other file is your private key (never share this).

If the ~/.ssh directory doesn’t exist or contains no key files, you need to generate one. Go to Fix 2.

If you do have a key pair, skip to Fix 3 to make sure it’s loaded, then Fix 4 to make sure GitHub has it.

Fix 2: Generate a New SSH Key

Generate an Ed25519 key (recommended over RSA for better security and shorter keys):

ssh-keygen -t ed25519 -C "[email protected]"

When prompted for a file location, press Enter to accept the default (~/.ssh/id_ed25519). Set a passphrase when prompted — it adds a layer of protection if someone gets access to your private key file.

If you’re on an older system that doesn’t support Ed25519, use RSA with a 4096-bit key:

ssh-keygen -t rsa -b 4096 -C "[email protected]"

Verify the key was created:

ls -la ~/.ssh

You should see id_ed25519 and id_ed25519.pub (or id_rsa and id_rsa.pub).

Fix 3: Add Your Key to the ssh-agent

The ssh-agent manages your SSH keys in memory so you don’t have to specify the key file manually every time.

macOS

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

The --apple-use-keychain flag stores the passphrase in your macOS Keychain so you won’t be prompted again after a restart.

To make this persist across reboots, add the following to ~/.ssh/config (create the file if it doesn’t exist):

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

Linux

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

If you want the agent to start automatically when you log in, add eval "$(ssh-agent -s)" to your ~/.bashrc or ~/.zshrc.

Windows (Git Bash)

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

If you’re using Windows PowerShell or the built-in OpenSSH, the ssh-agent is a Windows service:

# Run in an elevated PowerShell
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519

Fix 4: Add Your Public Key to GitHub / GitLab / Bitbucket

Copy your public key to the clipboard:

# macOS
pbcopy < ~/.ssh/id_ed25519.pub

# Linux (requires xclip)
xclip -selection clipboard < ~/.ssh/id_ed25519.pub

# Windows (Git Bash)
clip < ~/.ssh/id_ed25519.pub

# Or just print it and copy manually
cat ~/.ssh/id_ed25519.pub

Then add it to your hosting provider:

GitHub:

  1. Go to github.com/settings/keys
  2. Click New SSH key
  3. Give it a title (e.g., “Work Laptop”)
  4. Paste your public key
  5. Click Add SSH key

GitLab:

  1. Go to gitlab.com/-/user_settings/ssh_keys
  2. Paste your public key in the Key field
  3. Set an optional expiration date
  4. Click Add key

Bitbucket:

  1. Go to Personal settings > SSH keys
  2. Click Add key
  3. Paste your public key
  4. Click Add key

Fix 5: Test the Connection

Verify that SSH authentication works:

# GitHub
ssh -T [email protected]

# GitLab
ssh -T [email protected]

# Bitbucket
ssh -T [email protected]

A successful GitHub response looks like:

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

If you see Permission denied (publickey) again, SSH is still not using the right key. Run the connection with verbose output to debug:

ssh -vT [email protected]

Look for these lines in the output:

  • Offering public key: /home/you/.ssh/id_ed25519 — confirms SSH is trying your key.
  • Server accepts key — the server recognized your key.
  • No more authentication methods to try — none of your keys were accepted.

If SSH isn’t offering any keys, go back to Fix 3. If it offers a key but the server rejects it, the public key on GitHub doesn’t match — go back to Fix 4 and re-add it.

Why this matters: SSH keys are the foundation of secure Git authentication. If your key isn’t set up correctly, you can’t push, pull, or clone over SSH — which blocks your entire workflow. Fixing this once per machine saves hours of frustration.

Fix 6: Use HTTPS Instead of SSH

If you can’t get SSH working or just prefer a simpler setup, switch your remote to HTTPS:

# Check your current remote URL
git remote -v

# If it shows [email protected]:user/repo.git, change it to HTTPS:
git remote set-url origin https://github.com/user/repo.git

For GitLab:

git remote set-url origin https://gitlab.com/user/repo.git

With HTTPS, Git authenticates using a personal access token or credential manager instead of SSH keys. GitHub no longer accepts passwords for HTTPS Git operations — you’ll need a personal access token or the GitHub CLI (gh auth login). If the credential helper itself misbehaves, see Fix: Git credential helper not working.

Still Not Working?

Wrong file permissions on ~/.ssh

SSH refuses to use key files that are readable by other users. Fix the permissions:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/config

If permissions are wrong, SSH silently ignores the key file. This is a common issue on shared systems or when copying keys between machines.

Multiple GitHub accounts

If you have both a personal and a work GitHub account, SSH doesn’t know which key to use. Configure ~/.ssh/config with separate host aliases:

# Personal account
Host github.com-personal
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_personal

# Work account
Host github.com-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work

Then update your remotes to use the alias:

# For personal repos
git remote set-url origin [email protected]:your-personal-user/repo.git

# For work repos
git remote set-url origin [email protected]:your-work-user/repo.git

Corporate firewall blocking port 22

Some corporate networks block outgoing connections on port 22 (the default SSH port). GitHub and GitLab offer SSH over HTTPS port 443 as a workaround.

For GitHub, add this to ~/.ssh/config:

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

For GitLab, use:

Host gitlab.com
  HostName altssh.gitlab.com
  Port 443
  User git

Test the connection:

ssh -T -p 443 [email protected]

WSL2 SSH keys are separate from Windows

SSH keys inside WSL2 are stored in the Linux filesystem (~/.ssh inside your WSL distro), completely separate from your Windows keys (C:\Users\YourName\.ssh). If you set up keys in Windows but are running Git from WSL2, you need to either:

  • Generate a new key pair inside WSL2 and add it to GitHub, or
  • Copy your Windows keys into WSL2 and fix permissions:
cp /mnt/c/Users/YourName/.ssh/id_ed25519* ~/.ssh/
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub

Wrong remote URL

Your remote might be pointing to the wrong host or using the wrong format. Check it:

git remote -v

Make sure it matches the expected format:

A common mistake is having [email protected]/username/repo.git (forward slash instead of colon after the host). The correct SSH format uses a colon.

Common Mistake: Copying the HTTPS clone URL from GitHub and pasting it into a remote that expects SSH. The formats look similar but are fundamentally different: [email protected]:user/repo.git (SSH) vs https://github.com/user/repo.git (HTTPS).

Old RSA key signed with SHA-1

If you have a long-standing id_rsa key and connections suddenly started failing in 2022 or later, GitHub may be rejecting your signature algorithm. Run a verbose test:

ssh -vT [email protected] 2>&1 | grep -i signature

If you see ssh-rsa being offered but rejected, force the modern signature algorithm in ~/.ssh/config:

Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_rsa
  PubkeyAcceptedAlgorithms +ssh-rsa,rsa-sha2-256,rsa-sha2-512

The cleaner fix is to generate a new Ed25519 key and add it alongside your RSA key (see Fix 2). Newer key, no algorithm negotiation problem.

Stale entry in known_hosts after host key rotation

GitHub rotated its RSA host key in March 2023 after a private key exposure. If you saved the old key in ~/.ssh/known_hosts and connect with a verifying client, SSH refuses the connection with a host key mismatch warning rather than Permission denied (publickey). Remove the stale entry:

ssh-keygen -R github.com

Then connect again and accept the new host key. GitHub publishes the current fingerprints at docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints — verify before accepting.

IdentitiesOnly is off and the wrong key is offered first

SSH tries every key in ~/.ssh and every key loaded into the agent in the order they were added. If you have more than five keys, GitHub will close the connection after too many failures, even though one of the later keys would have worked. Pin the correct identity per host:

Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519
  IdentitiesOnly yes

IdentitiesOnly yes tells SSH to use only the specified key for this host, ignoring the rest of the agent. This also speeds up the connection.

Verbose debugging

If none of the above fixes work, run a verbose SSH connection to see exactly what’s happening:

ssh -vvT [email protected]

The -vv flag gives you detailed debug output. Look for:

  • Which config files are being loaded
  • Which identity files SSH is trying
  • Why the server rejected the authentication
  • Whether SSH is connecting to the right host and port

Share this output (redact any sensitive paths) if you need to ask for help. If the verbose output points to a connection-level problem rather than a key problem, see Fix: SSH connection timed out and Fix: ssh permission denied (publickey, password).


Related: Fix: git push rejected – non-fast-forward error

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles