SSH Permission Denied (publickey) — Find Which Key Was Rejected

Do not generate a new SSH key just because you see Permission denied (publickey). First prove the connection target and login user, then follow the intended key through the actual authentication transition: available → selected/offered → candidate accepted or rejected → signature succeeds → signed authentication accepted. Only then change client identity or server authorization. An “offered” key alone is not proof that public-key authentication completed.

OpenSSH · public key authenticationssh-agent · authorized_keysLast reviewed Sep 27, 2026
🎯 This guide matches when:
The TCP/SSH connection reaches authentication and ends with Permission denied (publickey) or a list including publickey.You expect public-key authentication to work for this host/user.You need to know whether the problem is client key selection or server/account authorization.
Read the authentication transition — then choose the branch
Wrong host or login user →A valid key for another account cannot authorize this target identity.Intended key is not available →Check the key file/agent/config before creating anything new.Key exists but is never offered →Fix identity selection, agent/config interaction or explicitly test the intended key.Correct key is offered but rejected →Move server-side: account authorization, authorized_keys, ownership/modes and sshd policy.Key is accepted but later operation fails →Authentication is solved. Diagnose repository, shell, SFTP or authorization after login separately.
Difficulty: ModerateRisk: Low · preserve access while testing
🔎 Quick Check — prove what SSH actually does
ssh -v user@host

Look for the resolved host/user and the authentication lines around Offering public key, Server accepts key, Authenticated to, or another Authentications that can continue. Exact wording varies by OpenSSH version. Also preserve any line that says the agent could not sign, a key/signature algorithm was refused, or another authentication method is still required—those are different branches from “the public key is simply absent from authorized_keys.”

Guardrail: Do not generate a new SSH key until verbose output proves the client lacks or cannot offer the intended key. A rejected key may already be perfectly valid cryptographically but unauthorized for this account.

Verify: you can state which host/user SSH is targeting and place the intended key at the furthest proven transition: absent, available-but-not-offered, offered/tested, candidate accepted but signing failed, signed request rejected, or fully authenticated.

Did verbose output identify the branch?
ADSENSE · reserved slot after the first useful step

Diagnostic flow — target → key → authorization

1
Target
Which hostname/IP and port did SSH actually reach?
2
User
Which remote account is being authenticated?
3
Available key
Does the intended private key exist or appear in the agent?
4
Offered key
Does verbose output prove that exact identity is offered?
5
Candidate / signature / authentication
Separate server acceptance of the key candidate from client signing and final acceptance of the signed authentication request.

Fix #2 — verify the target and remote user before touching keys

A public key authorizes an account on a particular SSH service; it does not grant universal access to a host. Check command-line user@host, Git remote URLs, host aliases and effective SSH configuration. Hosted Git services can require a service-specific SSH username—for example, GitHub's SSH endpoint uses git, not your GitHub account name.

ssh -G host | grep -E '^(hostname|user|port|identityfile) ' git remote -v

ssh -G prints the client's evaluated configuration; it is useful for checking values such as HostName, User, Port and IdentityFile, but it does not prove that a key was successfully loaded, signed with, offered, or accepted at runtime. Keep ssh -v as the runtime source of truth.

Verify: Verbose output connects to the intended host/port and shows the intended remote user before authentication begins.

Fix #3 — prove the intended private key is available

ssh-add -l shows identities currently held by the agent; it does not prove that a particular host connection will offer them. Also check whether the intended private-key file exists if you expect file-based discovery or an IdentityFile rule.

ssh-add -l -E sha256 ssh -G host | grep -i '^identityfile '

If the expected key is absent, determine whether it already exists under a non-default name, needs to be loaded into the appropriate agent, or should be referenced by host-specific config. Remember that configured IdentityFile entries and agent identities interact: OpenSSH can use agent identities in addition to configured identity files unless IdentitiesOnly restricts the set. Generate a new key only when you have established that the required identity truly does not exist or intentionally needs replacement.

Verify: You can identify the intended key by path or fingerprint without exposing the private key.

Fix #4 — key exists but SSH does not offer it

Test the intended identity explicitly. -i names an identity file; when multiple agent identities or config rules interfere, IdentitiesOnly=yes can restrict authentication to configured/explicit identities for the test.

ssh -v -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 user@host

IdentitiesOnly=yes is a selection control, not a repair by itself: it tells OpenSSH to use configured/explicit identities rather than every identity an agent may offer. If this controlled test works, make the selection host-specific in ~/.ssh/config rather than relying on a long global agent list. If your original error is instead Too many authentication failures, use the sibling guide because the server may disconnect before the intended identity is reached.

Verify: verbose output now contains the intended identity/fingerprint. Continue reading: determine whether the server rejects the candidate, accepts it but the client/agent cannot sign, rejects the signed authentication, requires another authentication method, or reaches Authenticated to.

Fix #5 — correct key is offered but the server rejects it

Once the intended key is demonstrably selected/offered, stop changing client key discovery unless the verbose transition shows a client signing problem. Verify that the matching public key is authorized for the same remote user and connection context. On a server you administer, inspect the account's effective sshd configuration—not only the first global line or an unqualified config dump. Match rules can depend on criteria such as user, source address/host and local address/port. Where supported, use sshd -T with the appropriate -C connection parameters to evaluate the context that actually failed. AuthorizedKeysFile, AuthorizedKeysCommand, PubkeyAuthentication, AuthenticationMethods and StrictModes can all alter acceptance. Check ownership/modes only against that effective policy and actual authorized-key source.

Server logs beat permission folklore. If you administer the host, correlate the failed attempt with sshd's authentication log/journal before changing modes. A rejection can be caused by account/key authorization, ownership/modes, an external AuthorizedKeysCommand, required multi-factor AuthenticationMethods, or key/signature policy. “Offered but rejected” does not uniquely mean authorized_keys permissions are wrong.

Do not loosen permissions broadly with chmod 777, disable StrictModes as a first fix, or replace authorized_keys wholesale. Preserve another working administrative session while changing remote access.

For managed Git/SSH services, compare the offered key's fingerprint with the key registered to the intended account/organization and consider service-side access policy. You may not have filesystem access to authorized_keys at all.

Verify: Retry the exact connection and confirm the server accepts the intended key for the intended account—without weakening authentication policy.

Fix #6 — key is offered, but signing or algorithm/policy fails

Do not collapse every post-offer transition into “wrong authorized_keys.” In the SSH public-key protocol, identifying/offering a key and completing a signed authentication request are distinct evidence points. Verbose output may show that the server is willing to consider a key but the agent cannot sign, that the client/server refuses a key or signature algorithm, that the signed request is rejected, or that public key is only the first step of an AuthenticationMethods chain. Preserve the exact transition and diagnose that branch rather than generating another key blindly.

For old RSA deployments in particular, distinguish the key from the signature algorithm negotiated for authentication. Avoid globally re-enabling legacy algorithms as a first response; prefer a supported server/client upgrade or the narrowest host-specific compatibility change when one is truly required.

Verify: The intended key can sign successfully, the negotiated authentication policy permits it, and verbose output progresses past the previously failing policy/signing step.

Fix #7 — the key is accepted: stop troubleshooting public-key authentication

If verbose output shows successful authentication, a later git push, shell, command, or SFTP failure is a different layer. Repository permissions, forced commands, shell restrictions and SFTP subsystem startup can all fail after identity authentication succeeds.

Scope boundary: successful authentication is the verification gate for this article. Do not rotate keys to solve an application authorization or subsystem error that occurs afterward.

Verify: Run the exact connection/test expected by the service and separate authentication success from the next failing operation.

What not to do

Do not generate a new key before proving the intended key is missing or cannot be offered.Do not paste or share a private key while asking for help; fingerprints and redacted verbose logs are enough for diagnosis.Do not use chmod 777 on ~/.ssh or authorized_keys.Do not disable StrictModes or public-key security controls merely to make the error disappear.Do not assume ssh-add -l proves the target connection actually offered that identity.Do not assume every offered-but-rejected key means bad authorized_keys permissions; inspect effective sshd policy and server logs when available.Do not globally re-enable deprecated/legacy SSH algorithms just to clear one host's authentication error.Do not use sudo git ... casually: elevation can change the user, home directory, agent/environment and therefore the identities available to SSH.Do not treat “Offering public key” as proof the key completed authentication; follow candidate acceptance, signing and final signed-request acceptance.Do not treat an unqualified sshd -T/global config view as proof of policy under Match rules; evaluate the actual user/source/local connection context when you administer the server.Do not overwrite authorized_keys while diagnosing one key; preserve existing working access and add/remove authorization deliberately.Do not keep diagnosing public-key selection once verbose output reaches Authenticated to; a later shell, Git, forced-command or SFTP failure is a new layer.

Still seeing Permission denied (publickey)?

Capture the authentication transition rather than the entire noisy log. The key question is where the chain first diverges: target, user, availability, offer, rejection or authorization.

Before escalating, capture:exact command or redacted Git remote and final errorresolved host, port and remote userfingerprint of the intended public key (never the private key)whether ssh-add -l lists the identityredacted verbose transition for the intended fingerprint: selected/offered, candidate acceptance/rejection, signing result, signed-request result and final authentication stateserver-side sshd authentication log/journal plus effective sshd authorization policy evaluated for the failing user/source/local connection context when you administer the serverany agent-signing, key/signature-algorithm or AuthenticationMethods line near the rejectionwhether the same key works for another account/host and whether another key works for this account

Official references

Still stuck? Ask the community

Share the target type, remote user, redacted verbose authentication transition and key fingerprint—not the private key.

Keep it safe: never post private keys, passphrases, tokens, internal hostnames/IPs or unredacted proprietary logs.
Powered by GitHub DiscussionsSign in with GitHub to comment. Reading comments does not require sign-in.

Loading community discussion…