Overview
The error "Permission denied (publickey)" means the SSH server rejected your authentication because it didn’t accept any public keys you offered. For Git (GitHub, GitLab, Bitbucket, or self-hosted), this typically stems from missing keys, wrong permissions, or an SSH client not offering the right key.
This guide shows how to quickly fix it, then diagnose deeper issues.
Quickstart (works on Linux, macOS, WSL, Windows OpenSSH)
- Generate a key (ED25519 is fast and secure):
ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519
- Start the agent and add your key:
# Linux/macOS/WSL
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# Windows PowerShell (OpenSSH)
Start-Service ssh-agent
Get-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
- Copy the public key and add it to your Git hosting account:
# Print the public key (copy the whole line)
cat ~/.ssh/id_ed25519.pub
- Test SSH:
ssh -T [email protected] # or [email protected], [email protected], etc.
- Use the SSH remote (not HTTPS):
git remote set-url origin [email protected]:org/repo.git
Minimal working example
Create a dedicated SSH config entry so the correct key is always used.
# ~/.ssh/config
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
AddKeysToAgent yes
Test the connection:
ssh -vT [email protected]
Clone using SSH:
git clone [email protected]:org/repo.git
If this works, the error should be gone for Git operations (fetch, pull, push).
Step-by-step diagnosis
- Check that a key exists
ls -l ~/.ssh
# Expect id_ed25519 and id_ed25519.pub (or id_rsa and id_rsa.pub)
If missing, generate a new key.
- Fix file and directory permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_* ~/.ssh/config
chmod 644 ~/.ssh/*.pub
- Ensure the key is loaded into ssh-agent
ssh-add -l # lists loaded keys
ssh-add ~/.ssh/id_ed25519
On Windows, ensure the OpenSSH Authentication Agent service is running.
- Force the client to offer the right key Use a host block in ~/.ssh/config with IdentitiesOnly yes and IdentityFile pointing to your key (see Minimal working example). Then:
ssh -o IdentitiesOnly=yes -vT [email protected]
- Verify the Git remote uses SSH
git remote -v
# If it shows https://..., switch to ssh
git remote set-url origin [email protected]:org/repo.git
- Confirm the correct username and host
- For hosted Git, User is always git.
- For self-hosted, confirm the SSH host, port, and user.
ssh -p 22 -vT [email protected]
If using a non-standard port:
Host git.example.com
Port 2222
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
- Validate the public key is registered server-side
- Hosted Git: ensure the same public key appears in your account’s SSH keys.
- Self-hosted: append the public key to ~/.ssh/authorized_keys on the Git server for the target user.
# On the server (for the git or repo user):
mkdir -p ~/.ssh && chmod 700 ~/.ssh
cat /tmp/your_key.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
- Inspect verbose output for clues
ssh -vvvT [email protected]
Look for lines like:
- Offering public key: ~/.ssh/id_ed25519
- Authentications that can continue: publickey
- Permission denied (publickey) If your key isn’t offered, fix the config or agent.
- Check for key type restrictions Some servers block weak or outdated keys. Prefer ED25519 or RSA 4096.
ssh-keygen -t rsa -b 4096 -C "[email protected]" -f ~/.ssh/id_rsa
Update IdentityFile if you switch keys.
- Handle multiple identities If you have many keys loaded, the server may reject after too many attempts. Limit what’s offered per host with IdentitiesOnly yes and a specific IdentityFile.
Permissions reference
| Path | Owner | Permissions |
|---|---|---|
| ~/.ssh | you | 700 |
| ~/.ssh/authorized_keys | you | 600 |
| ~/.ssh/id_ed25519 | you | 600 |
| ~/.ssh/id_ed25519.pub | you | 644 |
| ~/.ssh/config | you | 600 |
Common pitfalls
- Using HTTPS remote while testing SSH.
- Wrong username (use git for hosted services).
- Wrong key path or key not added to ssh-agent.
- Too many keys offered; server rejects before the right one.
- Key added to a different account than the one owning the repo.
- Non-standard SSH port not reflected in config.
- Home directory or .ssh directory owned by root (on servers) causing permission issues.
Performance notes
- Prefer ED25519 keys: faster than RSA with strong security.
- Enable connection multiplexing to speed repeated Git operations:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 10m
- Limit identities per host with IdentitiesOnly yes to reduce round-trips.
- Keep ssh-agent running so keys don’t need to be re-read for each Git command.
Example: multiple Git hosts
Host github.com
User git
HostName github.com
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host gitlab.com
User git
HostName gitlab.com
IdentityFile ~/.ssh/id_gitlab
IdentitiesOnly yes
Map each host to the correct key to avoid mismatches.
Tiny FAQ
Q: Do I have to regenerate my key? A: Not usually. First try loading the existing key into ssh-agent and fixing permissions.
Q: Can I use the same key for multiple Git hosts? A: Yes. You can reuse one key or create separate keys per host for isolation.
Q: Why does ssh -T work but git push fails? A: Your Git remote might still be HTTPS. Switch it to the SSH URL.
Q: Is RSA still okay? A: Yes, use at least 4096 bits. ED25519 is preferred for speed and simplicity.
Q: How do I test a non-standard port? A: Use ssh -p <port> host or set Port in the matching Host block in ~/.ssh/config.