SSH: Permission denied (publickey)
Hi, it's BlueByte. "Permission denied (publickey)" feels like a wall, but SSH will tell you exactly why if you ask it verbosely — you do not have to guess. Let's read what your client actually offered and what the server said, then fix the one thing that failed.
What the message means
A connection ends before you get a shell:
git@github.com: Permission denied (publickey).The server offered public-key authentication, none of the keys your client sent were accepted, and there was no password fallback. Which of those failed decides the fix — so ask SSH rather than guessing.
The three things that usually fail
Almost every case is one of these:
- Your key is not loaded into the agent, or the key file is not where SSH looks.
- The client is sending a different key than the one the server trusts — common when you have several keys and the agent offers the wrong one first.
- The server refuses the key over permissions — your
~/.sshdirectory or the private key file is readable by others, and SSH ignores keys with loose permissions.
Ask SSH which one it is
Run the connection verbosely and read which keys it offers and how the server responds:
ssh -vT git@github.comLook for Offering public key: ... followed by the server's answer. No key offered means it is not loaded; a key offered and rejected means the wrong key or a server that does not trust it; a Permissions ... are too open warning means the file mode is the problem. The verbose trace removes the guesswork.
Fix the one that failed
- No key offered — add yours to the agent:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519- Wrong key offered — pin the right one per host:
# ~/.ssh/config
Host github.com
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes- Rejected over permissions — tighten them; SSH ignores keys others can read:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519A real case: the agent offered an old key
You clone over SSH and get Permission denied (publickey). ssh -vT git@github.com shows it offering id_rsa (an old key) and the server rejecting it, never reaching your newer id_ed25519. So it is key selection, not a missing key. You add a Host github.com block with IdentityFile ~/.ssh/id_ed25519 and IdentitiesOnly yes, re-run ssh -vT, and this time it offers only the ed25519 key, which the server accepts with "successfully authenticated". The clone works.
Confirm the key is accepted
Test the authentication path without opening a shell:
ssh -T git@github.comA greeting like Hi <user>! You've successfully authenticated (even though it then closes the connection) means the key is accepted.
Keep it from recurring
Keep IdentitiesOnly yes in your SSH config so the agent does not throw every key at a server and trip a limit on attempts, register each new machine's public key with the service once, and keep ~/.ssh permissions tight so a synced dotfiles setup never loosens them.
How this differs from a connection or host-key error
Permission denied (publickey) is authentication failing after a connection. Connection refused or Connection timed out are earlier — the server is unreachable or nothing is listening on port 22 — and Host key verification failed is a changed server key, a different problem entirely. When you hit the publickey error, run ssh -vT first; the answer is almost always in that trace.
Related questions
ssh-add says 'Could not open a connection to your authentication agent'.
The agent is not running in this shell. Start it with eval "$(ssh-agent -s)" first, then ssh-add your key.
It works as my user but not with sudo. Why?
sudo runs as root, which has its own ~/.ssh and agent. Either do not use sudo for the SSH command, or configure the key for root explicitly.
The right key is added but the server still rejects it.
Confirm the matching public key is registered on the server or your account, and that you are using the SSH remote URL (git@host:org/repo.git), not HTTPS.
Why does IdentitiesOnly matter?
Without it the agent offers every key it holds; a server that limits authentication attempts can lock you out before it reaches the right one. IdentitiesOnly sends only the key you configured.
ssh -vT shows 'Too many authentication failures'.
The agent offered too many keys before the right one. Set IdentitiesOnly yes and point IdentityFile at the correct key so only it is tried.
References
Haneul Seo
Infrastructure engineer · 10+ years running Linux fleets
More in this category
systemd: Start request repeated too quickly
systemd refuses to start a unit that was started more than StartLimitBurst times (default 5) within StartLimitIntervalSec (default 10s), and Restart= counts against that limit. With the 100 ms default RestartSec a crashing service burns all five attempts in under a second. Find the real crash in the journal, fix it, run reset-failed, and give restarts room with RestartSec.
SSH: Received disconnect ... Too many authentication failures
Your agent is offering more keys than the server will let you try. Every public key sshd looks at burns one of the MaxAuthTries attempts — six by default, often three on a hardened host — so the right key never gets its turn and the server hangs up before you type anything. IdentitiesOnly=yes with an explicit IdentityFile pins the connection to one key and the attempt count drops to one.
Active Directory: replication fails with error 1722, The RPC server is unavailable
RPC reports 1722 (0x6ba, RPC_S_SERVER_UNAVAILABLE) when a lower layer fails to connect, so the real fault is almost never RPC itself — it is DNS, a blocked port, or a host-side setting on one of the two domain controllers. repadmin tells you which partner is failing, dcdiag /test:dns rules out name resolution, and Test-NetConnection plus the dynamic port range settle the firewall question. The most common miss is a rule that allows TCP 135 but not 49152–65535.
Windows Server RDS: The remote session was disconnected because there are no Remote Desktop License Servers available to provide a license
The 120-day RD Licensing grace period ended and the session host has no usable license server, so it refuses sessions. GetGracePeriodDays returning DaysLeft 0 and an empty SpecifiedLSList confirm it in seconds. The fix is a real, activated license server with CALs that are new enough for the host — a 2019 CAL cannot serve a 2022 session host — configured through the deployment or the Licensing policies, plus RPC ports open between the two.
Windows 11: "Your organization's security policies block unauthenticated guest access" when opening a NAS share (0x80070035)
The SMB client on Windows 10 Enterprise/Education/Pro for Workstations, Windows 11 Pro and Windows Server 2019+ refuses guest logons by default, and Windows 11 24H2 Enterprise/Pro/Education also requires SMB signing, which guest sessions can't do. A NAS share that only offers guest access therefore fails with the 'block unauthenticated guest access' dialog, Error code 0x80070035, or System error 3227320323, and Event ID 31017 'Rejected an insecure guest logon' lands in the SmbClient/Security log. The fix Microsoft recommends is a real account on the NAS and signing support in its firmware; Set-SmbClientConfiguration -EnableInsecureGuestLogons $true (plus -RequireSecuritySignature $false on 24H2) is the escape hatch, and it costs you signing and encryption on that client.
Ubuntu/Debian: E: Could not get lock /var/lib/dpkg/lock-frontend — who holds it and how to wait for it
Another package manager, usually Ubuntu's unattended-upgrades fired by a persistent systemd timer at boot, holds the dpkg frontend lock while your apt-get runs. apt-get gives up at once while apt waits because Ubuntu ships binary::apt::DPkg::Lock::Timeout "120" for the apt binary only. Read the PID from the message, let the run finish or pass -o DPkg::Lock::Timeout=<seconds> to apt-get, run dpkg --configure -a only after a genuinely interrupted run, and never delete the lock file: it is an fcntl lock the kernel releases when the holder exits.