Understanding the 'Permission denied (publickey)' Error
When you attempt to push, pull, or clone a Git repository over SSH and see the dreaded Permission denied (publickey) message, it means the SSH client was unable to authenticate with the remote server using your public key. The full error typically looks like 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.
This error occurs because SSH authentication relies on a cryptographic key pair — a private key stored locally on your machine and a corresponding public key that you register with the remote Git service (GitHub, GitLab, Bitbucket, or a self-hosted server). If any link in this chain is missing or misconfigured, authentication fails and Git halts the operation.
Why This Error Matters
SSH-based authentication is the most common and secure method for interacting with remote Git repositories. When it breaks, developers lose the ability to push code, deploy applications, or collaborate with team members. In production environments, CI/CD pipelines that rely on SSH to fetch dependencies or deploy builds will fail entirely. Understanding how to diagnose and fix this error is a fundamental skill that every developer should have — it saves hours of frustration and ensures uninterrupted workflow.
Step 1: Diagnose the Root Cause
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →Before applying fixes, determine exactly where the problem lies. Run the following diagnostic command to test your SSH connection to the remote host:
ssh -T git@github.com
Replace github.com with your Git provider's hostname (e.g., gitlab.com, bitbucket.org, or your company's Git server). The -T flag disables pseudo-terminal allocation, which is required for services that don't provide a shell. A successful connection returns a message like:
Hi username! You've successfully authenticated, but GitHub does not provide shell access.
If you see Permission denied (publickey), the problem is confirmed. Next, check whether your SSH agent is running and has your key loaded:
ssh-add -l
If the agent reports The agent has no identities or Could not open a connection to your authentication agent, you've found your culprit. If identities are listed but the connection still fails, the public key likely hasn't been added to your remote account, or the key permissions are incorrect.
List Your Existing Keys
Check which SSH keys exist on your local machine:
ls -la ~/.ssh/
Look for files named id_rsa, id_ed25519, id_ecdsa, or custom-named keys. The public key files end with .pub. If the directory is empty or lacks a key pair, you need to generate one.
Step 2: Generate a New SSH Key Pair
If you don't have an existing key or want to create a dedicated key for Git operations, generate one using the Ed25519 algorithm (preferred for its speed and security) or RSA as a fallback:
# Recommended: Ed25519
ssh-keygen -t ed25519 -C "your_email@example.com"
# Fallback for older systems that don't support Ed25519
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
The -C flag adds a comment (usually your email) to help identify the key's purpose. When prompted for a file path, press Enter to accept the default location (~/.ssh/id_ed25519 or ~/.ssh/id_rsa). You'll be asked to enter a passphrase — this adds an extra layer of security. Even if you leave it empty, the key will work, but using a strong passphrase is strongly recommended.
The output confirms where the key was saved and displays the key's fingerprint and randomart image:
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:abc123def456ghi789... your_email@example.com
Step 3: Add Your SSH Key to the SSH Agent
The SSH agent manages your private keys in memory so you don't need to enter the passphrase repeatedly. Start the agent and add your key:
# Start the SSH agent (if not already running)
eval "$(ssh-agent -s)"
# Add your private key to the agent
ssh-add ~/.ssh/id_ed25519
If you used a custom filename, specify that path instead. On macOS, the agent typically runs automatically. On Linux, you may need to add the eval line to your shell profile (~/.bashrc, ~/.zshrc) so the agent starts on login. On Windows with Git Bash or WSL, the same commands apply.
Persisting the SSH Agent Across Sessions (Linux/macOS)
Add these lines to your ~/.bashrc or ~/.zshrc to ensure the agent runs and loads your key automatically:
if [ -z "$SSH_AUTH_SOCK" ]; then
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519 2>/dev/null
fi
On macOS, you can also use the --apple-use-keychain flag to store the passphrase in the Keychain:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Step 4: Add Your Public Key to the Remote Git Service
Copy the contents of your public key file to the clipboard:
# On Linux/macOS
cat ~/.ssh/id_ed25519.pub
# On Windows (Command Prompt or PowerShell)
type ~/.ssh/id_ed25519.pub
# Alternatively, use a clipboard command
# macOS:
pbcopy < ~/.ssh/id_ed25519.pub
# Linux (requires xclip):
xclip -selection clipboard < ~/.ssh/id_ed25519.pub
# Windows PowerShell:
Get-Content ~/.ssh/id_ed25519.pub | clip
Now navigate to your Git provider's SSH key settings page and paste the entire key, including the ssh-ed25519 prefix and the trailing comment:
- GitHub: Settings → SSH and GPG Keys → New SSH Key
- GitLab: Preferences → SSH Keys → Add Key
- Bitbucket: Personal Settings → SSH Keys → Add Key
- Azure DevOps: User Settings → SSH Public Keys → Add Key
Give the key a descriptive title (e.g., "Work Laptop - January 2025") so you can identify it later. After adding the key, test the connection again:
ssh -T git@github.com
You should see the success message confirming authentication. If prompted to accept the host's fingerprint, type yes — this adds the host to your ~/.ssh/known_hosts file and only happens once per host.
Step 5: Handle Multiple SSH Keys
Many developers maintain separate SSH keys for different purposes (personal GitHub, work GitLab, deployment servers). The SSH client doesn't automatically know which key to use for which host. To solve this, create or edit the SSH configuration file:
# Create or open the SSH config file
nano ~/.ssh/config
Add host-specific entries that map identities to hostnames:
# Personal GitHub account
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
IdentitiesOnly yes
# Work GitLab account
Host gitlab.work.com
HostName gitlab.work.com
User git
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
# Self-hosted server on non-standard port
Host myserver
HostName myserver.example.com
Port 2222
User deploy
IdentityFile ~/.ssh/id_rsa_server
The IdentitiesOnly yes directive ensures SSH only uses the specified key and doesn't try all available keys sequentially — this prevents the server from rejecting you after too many failed attempts. After saving the config, test each host individually:
ssh -T git@github.com
ssh -T git@gitlab.work.com
Step 6: Fix Common File Permission Issues
SSH is extremely strict about file permissions. If your private key or the ~/.ssh directory has overly permissive access rights, SSH will refuse to use the key — often with a different but related error message. Set the correct permissions:
# Set ~/.ssh directory permissions to 700 (read/write/execute for owner only)
chmod 700 ~/.ssh
# Set private key permissions to 600 (read/write for owner only)
chmod 600 ~/.ssh/id_ed25519
# Set public key permissions to 644 (readable by all, writable by owner)
chmod 644 ~/.ssh/id_ed25519.pub
# Ensure the authorized_keys file (if you use it) has correct permissions
chmod 600 ~/.ssh/authorized_keys
# The known_hosts file should be 644
chmod 644 ~/.ssh/known_hosts
These commands apply to Linux and macOS. On Windows, the OpenSSH client enforces similar restrictions, but the permission model differs — ensure your .ssh directory is stored in a location only your user account can access (typically C:\Users\YourName\.ssh).
Step 7: Verify the Remote URL Uses SSH, Not HTTPS
Sometimes the error appears because the repository's remote URL is configured to use HTTPS instead of SSH. Check the remote URL:
git remote -v
SSH URLs follow the format git@github.com:username/repo.git, while HTTPS URLs look like https://github.com/username/repo.git. If you see an HTTPS URL and want to switch to SSH:
git remote set-url origin git@github.com:username/repo.git
Replace origin with the remote name if different, and substitute the correct hostname, username, and repository path. After changing the URL, test with a fetch:
git fetch origin
Troubleshooting Edge Cases
Agent Forwarding Issues
If you're SSHing into a remote server and trying to run Git commands from there (a common pattern for deployment), you need agent forwarding. Add this to your ~/.ssh/config:
Host myserver
ForwardAgent yes
Then ensure your local agent has the key loaded and you connect with ssh -A (or rely on the config). On the remote server, run ssh-add -l to confirm the forwarded key is visible.
RSA Key Rejection by Modern Servers
Some Git providers (including GitHub) have deprecated RSA keys using SHA-1 signatures. If you generated an RSA key with ssh-keygen -t rsa before 2022, you may encounter Permission denied even with a correctly configured key. Generate a new Ed25519 key or an RSA key with SHA-2 signatures:
ssh-keygen -t rsa -b 4096 -E sha2 -C "your_email@example.com"
Then upload the new public key to your provider and update your SSH config accordingly.
Corporate VPN or Proxy Interference
Corporate networks sometimes route SSH traffic through proxies that strip or alter authentication packets. If you're on a VPN and suddenly get the publickey error, try:
- Disconnecting and reconnecting to the VPN
- Using SSH over HTTPS (available on some providers via
ssh.github.comon port 443) - Contacting your IT department to ensure outbound SSH on port 22 is allowed
Debugging with Verbose Output
When all else fails, SSH's verbose mode reveals exactly where authentication breaks down:
ssh -vT git@github.com
Increase verbosity with -vv or -vvv for more detail. Look for lines like:
Authentications that can continue: publickey— confirms the server expects a keyOffering public key: /home/user/.ssh/id_ed25519— shows which keys are being triedReceived disconnect— indicates the server rejected the key
This output is invaluable for pinpointing whether the issue is a missing key, wrong key, or network-level problem.
Best Practices for SSH Key Management
- Use Ed25519 keys whenever possible. They are faster, more secure, and generate smaller signatures than RSA keys.
- Always set a passphrase on your SSH keys. It protects your private key if your machine is compromised. Use
ssh-agentto avoid typing the passphrase repeatedly. - Rotate keys periodically — especially for production deployment access. Treat SSH keys like credentials: revoke and regenerate them if they're exposed.
- Never share private keys. Each developer and each machine should have its own key pair. Sharing private keys makes auditing impossible and increases the blast radius of a compromise.
- Use the SSH config file (
~/.ssh/config) to manage multiple keys cleanly. Avoid relying on the agent trying keys sequentially. - Audit your registered public keys on GitHub, GitLab, and other services quarterly. Remove keys for machines you no longer use.
- Back up your private keys securely (e.g., in an encrypted password manager). Losing a key with no backup means losing access to any service that only trusts that key.
Conclusion
The Git Permission denied (publickey) error is a gatekeeper moment — it signals a break in the SSH authentication chain that every developer must understand to work effectively. The fix almost always boils down to four steps: verify you have a key pair, ensure the SSH agent has your private key loaded, confirm the corresponding public key is registered with your Git provider, and check that file permissions and remote URLs are correct. By mastering the diagnostic commands and configuration techniques outlined here, you can resolve this error in minutes rather than hours and build a robust SSH key management practice that scales across personal projects, team workflows, and production deployments. Keep your keys secure, your config file organized, and your agent running — and you'll never stare at that permission denied message in frustration again.