Fix SSH Permission denied (publickey) without weakening authentication
Trace the SSH user, host, selected key, agent, server policy, authorized_keys path, permissions, and authentication log before changing access controls.
Restore key-based SSH access for the intended account while keeping password login, host verification, and unrelated accounts unchanged.
- OpenSSH client 9.x, 10.x
- OpenSSH server 9.x, 10.x
- Fallback access Keep console access or a second authenticated session before editing server authorization files.
- Expected identity Know the intended SSH username, hostname, port, and public-key fingerprint.
- Server evidence Have permission to read effective sshd configuration and the authentication journal or log.
OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.
Full guide
What you will build
- A repeatable OpenSSH incident record that starts with the literal `Permission denied (publickey)` symptom and preserves the first useful failure instead of hiding it with an early restart or broad permission change.
- A layer-by-layer decision path from client context through configuration and runtime evidence to one narrowly scoped remediation, followed by positive and negative verification.
- A reusable evidence bundle containing commands, concrete example output, timestamps, identities, effective configuration, and stop conditions that another operator can review without access to the original terminal.
- You can identify which boundary failed, explain why competing hypotheses were rejected, and state what changed before declaring the incident resolved.
- The repaired path succeeds under the intended identity while an unauthorized or incorrect path still fails, proving that the fix did not simply remove a security control.
- The final evidence distinguishes a transient recovery from a durable repair by checking logs, counters, configuration provenance, and the original user-visible operation.
Architecture
How the parts fit together
OpenSSH troubleshooting is treated as an evidence pipeline rather than a list of guesses. The operator captures the symptom, resolves client and target context, inspects the first authoritative server-side failure, tests the smallest cause boundary, applies one reviewed change, and repeats the same observation path. This keeps a secondary error from replacing the primary cause and makes rollback possible.
- Copy the literal error and the command that produced it before retrying, restarting, pruning, resetting, or editing anything.
- Resolve the selected identity, configuration, target, and current runtime state so later commands inspect the same path the user exercised.
- Read the nearest authoritative log or effective configuration and align timestamps across the client and server evidence.
- Test one hypothesis with a read-only command; if evidence disagrees, return to the previous layer instead of stacking speculative changes.
- Back up the affected configuration or reference, apply the narrow repair, validate syntax, and reload only the component that owns the decision.
- Repeat the original action plus a negative control, record the outcome, and keep rollback material until the observation window is complete.
Assumptions
- The host key has already been verified through a trusted channel; this tutorial does not bypass a changed-host-key warning.
- The server is reachable and completes SSH transport negotiation, so the failure occurs during user authentication.
- The intended private key remains local and readable only by its owner; only its public fingerprint is recorded in evidence.
- Clocks are close enough that client and server timestamps can be correlated. If they are not, record the offset before comparing logs.
- The operator has a recovery path that does not depend on the component being changed, such as console access, a second session, or a preserved remote reference.
- Commands are first run in the affected environment with placeholders reviewed. OneLiners never executes them and does not know local policy, tenancy, or maintenance constraints.
Key concepts
- Authentication user
- The account name before the host in user@host; a correct key authorized for another user still fails.
- Identity selection
- The client chooses keys from explicit IdentityFile directives and an agent; IdentitiesOnly limits offers to reviewed identities.
- authorized_keys
- The server-side public-key list whose path, ownership, modes, restrictions, and content are evaluated for the target user.
- StrictModes
- An sshd check that rejects unsafe ownership or permissions on the user's home, .ssh directory, and authorization file.
- Effective configuration
- The final client or server settings after includes, host blocks, Match rules, command-line flags, and defaults are applied.
Fill these once. Every matching command and configuration block updates immediately; values stay in this page only.
Security and production boundaries
- Treat access restoration as an identity change: prove the user, source, key fingerprint, and authorized scope before repair.
- PasswordAuthentication and StrictHostKeyChecking must not be disabled as diagnostic shortcuts.
- Do not paste private keys, tokens, complete environment dumps, authorization headers, or unredacted customer data into tickets or external analysis tools.
- A successful operation after disabling authentication, trust, host verification, sandboxing, or least privilege is a security regression, not a valid repair.
- Prefer effective configuration and narrow identity tests over recursive ownership changes, mode 777, global trust bypasses, or force options copied from unrelated incidents.
Stop before continuing if
- Stop on any unexplained host-key change and verify the host out of band.
- Stop if the intended account, key owner, or source network cannot be proven.
- Stop if the target, account, environment, repository, or service instance cannot be identified unambiguously.
- Stop before a destructive cleanup, force update, broad permission change, or production reload when backup and recovery evidence is missing.
- Stop if the proposed action would conceal the first error or remove logs, failed objects, repository references, or configuration needed for diagnosis.
instruction
Freeze the symptom and define the incident boundary
Before changing OpenSSH, preserve the literal `Permission denied (publickey)` message, the exact action that produced it, the affected identity, target, UTC time, and expected result. Decide which production boundary is in scope and name the independent recovery path you will keep available.
Why this step matters
A retry, restart, cleanup, permission change, or configuration edit can replace the primary failure with a secondary one. A fixed starting record lets every later check answer a specific hypothesis.
What to understand
Record whether the problem affects one user or workload, one target, one host, or every comparable path; this determines whether to begin at the client, transport, or service boundary.
Write down the expected successful behavior in observable terms such as an exit status, HTTP response, remote object ID, authenticated principal, or stable service state.
Keep console access, a second session, an earlier configuration, or a recoverable reference independent of the component being diagnosed.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Incident scope Tool: OpenSSH Observed: `Permission denied (publickey)` Affected target: production-app-01 Observed at: 2026-08-17T14:02:11Z Expected: the reviewed operation completes without weakening an access or safety control Recovery path: console session and last known-good configuration retained
Security notes
- Redact secrets and customer data, but retain error text, timestamps, object IDs, modes, owners, and target names needed to reproduce the decision.
Alternatives
- When direct production inspection is restricted, reproduce the same version and configuration boundary in an isolated environment and mark which evidence is illustrative.
Stop conditions
- Stop before any mutation if the target, identity, affected environment, expected result, or recovery path is still ambiguous.
command
Capture the key offer and server decision
Run one verbose connection with an explicit user, port, and identity. Keep the lines around Offering public key, Server accepts key, and Authentications that can continue.
Why this step matters
Verbose client output proves which key was actually offered and whether the server rejected it, avoiding guesses based on filenames or agent contents.
What to understand
Use one explicit key so Too many authentication failures and agent ordering cannot obscure the result.
The absence of Offering public key means the problem is local selection or key readability; a rejection after offering moves the investigation server-side.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Syntax explained
-vvv- Emits protocol and authentication decisions without printing private-key material.
IdentitiesOnly=yes- Prevents unrelated agent keys from being offered for this controlled test.
-i / -p- Selects the reviewed identity file and service port explicitly.
Values stay on this page and are never sent or saved.
ssh -vvv -o IdentitiesOnly=yes -i {{keyPath}} -p {{port}} {{user}}@{{host}} truedebug1: Offering public key: /home/alice/.ssh/id_ed25519_deploy ED25519 SHA256:4mY... explicit debug1: Authentications that can continue: publickey deploy@app01.example.net: Permission denied (publickey).
Checkpoint: Checkpoint: Capture the key offer and server decision
ssh -vvv -o IdentitiesOnly=yes -i {{keyPath}} -p {{port}} {{user}}@{{host}} trueContinue whenThe intended fingerprint is offered to the intended user and host; the exact rejection point is visible.
Stop whenThe host key is new or changed, the target address is unexpected, or the intended key is not the one offered.
If this step fails
The client reports Load key: invalid format or error in libcrypto.
Likely causeThe key file is damaged, is a public key passed as a private key, has altered line endings, or is in an unsupported format.
file {{keyPath}}ssh-keygen -y -f {{keyPath}} >/dev/null
ResolutionRecover the original private key from a trusted source or issue a new key; do not edit key body lines manually.
Security notes
- Verbose logs can expose usernames, hostnames, and paths; redact them before external sharing.
Alternatives
- Use `ssh -G` first when policy forbids even a failed authentication attempt.
Stop conditions
- The host key is new or changed, the target address is unexpected, or the intended key is not the one offered.
command
Resolve the effective SSH client configuration
Inspect the final hostname, user, port, identity files, proxy path, and authentication controls after all Host and Include rules are applied.
Why this step matters
Aliases, wildcard Host blocks, includes, and jump hosts frequently change the real destination or identity even when the typed command looks correct.
What to understand
Compare hostname and user with the server you can inspect; a ProxyJump means authentication may occur on more than one host.
Multiple IdentityFile rows are ordered inputs, not proof that a particular private key exists or was accepted.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Syntax explained
ssh -G- Prints evaluated client configuration without opening a network connection.
Values stay on this page and are never sent or saved.
ssh -G -p {{port}} {{user}}@{{host}} | grep -E '^(hostname|user|port|identityfile|identitiesonly|proxyjump|proxycommand) 'hostname app01.example.net user deploy port 22 identityfile ~/.ssh/id_ed25519_deploy identitiesonly yes
Checkpoint: Checkpoint: Resolve the effective SSH client configuration
ssh -G -p {{port}} {{user}}@{{host}} | grep -E '^(hostname|user|port|identityfile|identitiesonly|proxyjump|proxycommand) 'Continue whenThe effective destination, user, port, proxy, and identity match the intended access path.
Stop whenA proxy, hostname rewrite, unexpected user, or organization-managed include changes the target path.
If this step fails
The expected IdentityFile does not appear.
Likely causeA Host pattern does not match, an Include is missing, or a later command-line choice overrides configuration.
ssh -G {{host}} | grep '^identityfile '
ResolutionCorrect the narrow Host block or invoke the explicit identity; do not replace global client configuration.
Security notes
- Do not remove host-key checking or ProxyJump policy to make the path simpler.
Alternatives
- Use a temporary `-F` file containing only the reviewed host block for a controlled comparison.
Stop conditions
- A proxy, hostname rewrite, unexpected user, or organization-managed include changes the target path.
command
Compare local, agent, and authorized fingerprints
Derive the public fingerprint from the private key, list agent identities, and compare only fingerprints with the authorized server entry.
Why this step matters
A filename, comment, or copied public-key label is not identity evidence; the cryptographic fingerprint must match across the client and server.
What to understand
`ssh-keygen -y` reads the private key and emits only its public half into the fingerprint command.
An agent may hold an older or unrelated key; the explicit-key test remains authoritative for this incident.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Syntax explained
ssh-keygen -y- Derives the public key from the private key without displaying private material.
ssh-keygen -lf -- Prints the fingerprint of the public key received on standard input.
ssh-add -l- Lists fingerprints currently offered by the authentication agent.
Values stay on this page and are never sent or saved.
ssh-keygen -y -f {{keyPath}} | ssh-keygen -lf - && ssh-add -l256 SHA256:4mYf8f0R... deploy@app01 (ED25519) 256 SHA256:pQ3cA7... workstation (ED25519)
Checkpoint: Checkpoint: Compare local, agent, and authorized fingerprints
ssh-keygen -y -f {{keyPath}} | ssh-keygen -lf - && ssh-add -lContinue whenThe explicit private key has the expected public fingerprint; agent differences are understood.
Stop whenThe key cannot be read, its fingerprint is unknown, or it does not match the approved public key.
If this step fails
ssh-add reports that the agent has no identities.
Likely causeThe controlled path depends on an unloaded agent key instead of the explicit identity.
printf '%s ' "$SSH_AUTH_SOCK"ssh-add -l
ResolutionUse the explicit reviewed key or load it into the correct session agent according to local policy.
Security notes
- Never send the private key to the server or include it in evidence; fingerprints are sufficient.
Alternatives
- Compare the `.pub` file fingerprint directly when private-key access is intentionally delegated to hardware.
Stop conditions
- The key cannot be read, its fingerprint is unknown, or it does not match the approved public key.
command
Inspect effective sshd policy and authorization path
Evaluate sshd for the target user and inspect the home, .ssh directory, authorization file, ownership, modes, and matching public fingerprint.
Why this step matters
The server makes the authorization decision from effective Match-aware policy, path traversal permissions, file ownership, modes, and key options.
What to understand
Supply the real client address when Match Address rules exist; a placeholder address can produce the wrong effective policy.
`namei -l` exposes every parent component, which catches an unsafe or inaccessible home directory that a final-file `ls` misses.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Syntax explained
sshd -T -C- Prints effective server configuration for a simulated user, host, and client address.
namei -l- Shows ownership and mode for every path component.
ssh-keygen -lf authorized_keys- Lists fingerprints of authorized public keys without private data.
Values stay on this page and are never sent or saved.
sudo sshd -T -C user={{user}},host={{host}},addr=192.0.2.10 | grep -E '^(pubkeyauthentication|authorizedkeysfile|strictmodes|authenticationmethods) ' && sudo namei -l /home/{{user}}/.ssh/authorized_keys && sudo ssh-keygen -lf /home/{{user}}/.ssh/authorized_keyspubkeyauthentication yes authorizedkeysfile .ssh/authorized_keys .ssh/authorized_keys2 strictmodes yes f: /home/deploy/.ssh/authorized_keys -rw------- deploy deploy authorized_keys 256 SHA256:4mYf8f0R... deploy@app01 (ED25519)
Checkpoint: Checkpoint: Inspect effective sshd policy and authorization path
sudo sshd -T -C user={{user}},host={{host}},addr=192.0.2.10 | grep -E '^(pubkeyauthentication|authorizedkeysfile|strictmodes|authenticationmethods) ' && sudo namei -l /home/{{user}}/.ssh/authorized_keys && sudo ssh-keygen -lf /home/{{user}}/.ssh/authorized_keysContinue whenPublic-key authentication is enabled, the path is the expected one, modes pass StrictModes, and the intended fingerprint is present.
Stop whenA Match rule, centralized AuthorizedKeysCommand, unknown key restriction, or account policy owns authorization instead of the inspected file.
If this step fails
sshd -T reports an unsupported or invalid option.
Likely causeThe command is running against a different sshd build or configuration than the active service.
sudo sshd -tsystemctl cat sshd 2>/dev/null || systemctl cat ssh
ResolutionLocate the active daemon configuration and validate it before editing; do not reload a configuration that fails `sshd -t`.
Security notes
- Preserve key restrictions such as `from=`, `command=`, or certificate-authority; they may be the intended control.
Alternatives
- Inspect the configured AuthorizedKeysCommand output when authorization is centrally managed.
Stop conditions
- A Match rule, centralized AuthorizedKeysCommand, unknown key restriction, or account policy owns authorization instead of the inspected file.
command
Read the authoritative authentication rejection
Correlate one controlled failed attempt with the SSH service journal and record the server reason, source address, target user, and key fingerprint when available.
Why this step matters
The client intentionally gives a generic denial, while the server log often identifies StrictModes, account state, key restrictions, algorithm policy, or lookup failures.
What to understand
Filter by the test timestamp, source address, and user; unrelated internet scans can otherwise dominate the log.
If the service logs elsewhere, inspect the configured facility or distribution authentication log without changing verbosity in production first.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Syntax explained
-u ssh.service -u sshd.service- Covers common Debian/Ubuntu and RHEL-family unit names.
--since- Bounds evidence to the controlled attempt.
sudo journalctl -u ssh.service -u sshd.service --since '-10 minutes' --no-pager | tail -n 80Aug 17 11:42:18 app01 sshd[18422]: Authentication refused: bad ownership or modes for file /home/deploy/.ssh/authorized_keys Aug 17 11:42:18 app01 sshd[18422]: Connection closed by authenticating user deploy 192.0.2.10 port 51422 [preauth]
Checkpoint: Checkpoint: Read the authoritative authentication rejection
sudo journalctl -u ssh.service -u sshd.service --since '-10 minutes' --no-pager | tail -n 80Continue whenOne server-side reason aligns with the controlled client attempt and the intended target account.
Stop whenNo matching attempt reaches the server, logs identify a different source/username, or centralized authentication is unavailable.
If this step fails
No authentication record appears.
Likely causeThe request reached another host/port, was blocked before sshd, or logs use another destination.
getent ahosts {{host}}ssh -G {{host}} | grep -E '^(hostname|port|proxyjump) '
ResolutionRe-establish the real target path before changing server authorization.
Security notes
- Authentication logs contain user and network identifiers; retain them according to incident policy.
Alternatives
- Use the distribution authentication log when journald forwarding or unit filtering is not authoritative.
Stop conditions
- No matching attempt reaches the server, logs identify a different source/username, or centralized authentication is unavailable.
decision
Repair one demonstrated cause and verify both boundaries
Back up the authorization file, correct only the demonstrated ownership/mode or key entry, validate sshd, and test the intended key plus an unauthorized key from a second session.
Why this step matters
A narrow, backed-up repair preserves the key-only boundary and proves the intended identity rather than merely making an SSH prompt disappear.
What to understand
Apply ownership or mode changes only when the log proved StrictModes was the cause; otherwise repair the specific key, user, or Match policy.
Keep the fallback session open until `sshd -t`, positive login, negative login, and a fresh journal review all succeed.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- Creates one rollback copy and may change ownership or mode of the target user's .ssh directory and authorization file; it does not enable passwords or reload sshd.
Syntax explained
cp -a- Preserves the prior authorization file and metadata for rollback.
chmod 700/600- Removes group/other access from the authorization directory and file.
sshd -t- Validates server configuration syntax before any reload is considered.
Values stay on this page and are never sent or saved.
sudo cp -a /home/{{user}}/.ssh/authorized_keys /home/{{user}}/.ssh/authorized_keys.before-oneliners && sudo chown {{user}}:{{user}} /home/{{user}}/.ssh /home/{{user}}/.ssh/authorized_keys && sudo chmod 700 /home/{{user}}/.ssh && sudo chmod 600 /home/{{user}}/.ssh/authorized_keys && sudo sshd -t && ssh -o IdentitiesOnly=yes -i {{keyPath}} -p {{port}} {{user}}@{{host}} 'id && printf authorized'uid=1002(deploy) gid=1002(deploy) groups=1002(deploy) authorized
Checkpoint: Checkpoint: Repair one demonstrated cause and verify both boundaries
sudo cp -a /home/{{user}}/.ssh/authorized_keys /home/{{user}}/.ssh/authorized_keys.before-oneliners && sudo chown {{user}}:{{user}} /home/{{user}}/.ssh /home/{{user}}/.ssh/authorized_keys && sudo chmod 700 /home/{{user}}/.ssh && sudo chmod 600 /home/{{user}}/.ssh/authorized_keys && sudo sshd -t && ssh -o IdentitiesOnly=yes -i {{keyPath}} -p {{port}} {{user}}@{{host}} 'id && printf authorized'Continue whenThe intended key logs in as the intended account, unauthorized keys remain denied, and the journal contains no policy bypass or new warning.
Stop whenOwnership is centrally managed, the home layout differs, the backup fails, sshd validation fails, or the negative test unexpectedly succeeds.
If this step fails
The intended key still fails after permissions are corrected.
Likely causeThe original cause was a user, key, Match, restriction, algorithm, account, or centralized lookup mismatch rather than StrictModes.
sudo sshd -T -C user={{user}},host={{host}},addr=192.0.2.10sudo journalctl -u sshd --since '-5 minutes' --no-pager
ResolutionRestore the prior file if changed unnecessarily and continue from the new authoritative log reason.
Security notes
- Never use recursive chown on the whole home or chmod 777; either can expose secrets and mask the actual policy boundary.
Alternatives
- Issue a new restricted key through the organization's identity workflow when the approved key cannot be recovered.
Stop conditions
- Ownership is centrally managed, the home layout differs, the backup fails, sshd validation fails, or the negative test unexpectedly succeeds.
verification
Observe for recurrence and close with evidence
After the original OpenSSH operation succeeds, repeat the same read-only observation path used at the start. Watch the relevant logs, counters, identities, and target state for a bounded period, then record the proven cause, exact change, verification result, rollback point, and remaining uncertainty.
Why this step matters
A single successful retry may be a transient recovery. Repeating the original checks and retaining the rollback point distinguishes a durable repair from a restart-only improvement.
What to understand
Use the same client identity, target, path, and configuration selection as the original failure so the positive result is comparable.
Include one negative or unauthorized control where safe; this proves the repair did not work by removing authentication, trust, isolation, or branch protection.
Keep the evidence concise enough for another operator to reproduce, but include software versions and exact object or configuration references.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Observation window: 15 minutes Original operation: PASS Original signature recurrences: 0 Negative control: PASS Rollback point retained: yes Cause and repair recorded: yes Remaining uncertainty: none observed within the stated boundary
Checkpoint: Checkpoint: the repair remains valid
sudo cp -a /home/{{user}}/.ssh/authorized_keys /home/{{user}}/.ssh/authorized_keys.before-oneliners && sudo chown {{user}}:{{user}} /home/{{user}}/.ssh /home/{{user}}/.ssh/authorized_keys && sudo chmod 700 /home/{{user}}/.ssh && sudo chmod 600 /home/{{user}}/.ssh/authorized_keys && sudo sshd -t && ssh -o IdentitiesOnly=yes -i {{keyPath}} -p {{port}} {{user}}@{{host}} 'id && printf authorized'Continue whenThe intended operation stays healthy, the original signature does not recur, and the negative control still enforces the expected boundary.
Stop whenThe result depends on an unexplained retry, disabled control, different target, or unrecorded manual state.
If this step fails
The error returns during the observation window.
Likely causeThe change treated a symptom, another instance still has the old state, or an automated process reverted or recreated the failing condition.
ssh -vvv -o IdentitiesOnly=yes -i {{keyPath}} -p {{port}} {{user}}@{{host}} truesudo cp -a /home/{{user}}/.ssh/authorized_keys /home/{{user}}/.ssh/authorized_keys.before-oneliners && sudo chown {{user}}:{{user}} /home/{{user}}/.ssh /home/{{user}}/.ssh/authorized_keys && sudo chmod 700 /home/{{user}}/.ssh && sudo chmod 600 /home/{{user}}/.ssh/authorized_keys && sudo sshd -t && ssh -o IdentitiesOnly=yes -i {{keyPath}} -p {{port}} {{user}}@{{host}} 'id && printf authorized'
ResolutionPreserve the recurrence, compare it with the first evidence set, restore the known-good state if necessary, and reopen the unresolved layer instead of stacking another repair.
Security notes
- Store only redacted operational evidence and remove temporary debug output according to local retention policy after review.
Alternatives
- Use the service's approved monitoring or audit trail when an interactive observation window is not practical.
Stop conditions
- Do not close the incident while the result is intermittent, the rollback point is missing, or a safety control remains weakened.
Finish line
Verification checklist
sudo cp -a /home/{{user}}/.ssh/authorized_keys /home/{{user}}/.ssh/authorized_keys.before-oneliners && sudo chown {{user}}:{{user}} /home/{{user}}/.ssh /home/{{user}}/.ssh/authorized_keys && sudo chmod 700 /home/{{user}}/.ssh && sudo chmod 600 /home/{{user}}/.ssh/authorized_keys && sudo sshd -t && ssh -o IdentitiesOnly=yes -i {{keyPath}} -p {{port}} {{user}}@{{host}} 'id && printf authorized'The operation completes with exit status 0 and without the original error. The output identifies the intended host, service, repository, or endpoint.ssh -vvv -o IdentitiesOnly=yes -i {{keyPath}} -p {{port}} {{user}}@{{host}} trueA fresh diagnostic capture shows the healthy path and no recurrence of the original signature. Logs and counters remain stable during the observation window.Recovery guidance
Common problems and safe checks
The client offers many keys and the server disconnects with Too many authentication failures.
Likely causeAn agent exhausts MaxAuthTries before the intended key is offered.
ssh-add -lssh -vvv -o IdentitiesOnly=yes -i {{keyPath}} {{user}}@{{host}}
ResolutionUse IdentitiesOnly for the host and configure the intended IdentityFile; do not raise MaxAuthTries globally.
The key is present but a `from=` restriction rejects the client.
Likely causeThe source address changed or traffic now exits through another gateway.
curl -4 https://ifconfig.co 2>/dev/nullsudo journalctl -u sshd --since '-10 minutes'
ResolutionVerify the new trusted source path and update the narrow restriction through change control if intended.
A hardware-backed key works interactively but not in automation.
Likely causeThe job lacks the agent, user presence, or FIDO capability required by the key.
ssh-add -Lssh -Q key
ResolutionUse an automation-specific restricted credential or certificate rather than exporting the human private key.
Reference
Frequently asked questions
Should I enable password login temporarily?
No. A public-key failure has a specific user, identity, policy, path, or permission cause. Enabling another method expands exposure and removes evidence that the key path was actually repaired.
Does chmod 600 always fix authorized_keys?
No. Parent ownership, home permissions, Match rules, key options, AuthorizedKeysCommand, account state, algorithms, and the selected username also affect authorization.
Why does the key work for one host alias but not another?
Host blocks and Includes can choose a different hostname, port, user, identity, proxy, or IdentitiesOnly value. Compare `ssh -G` output for both names.
Can I copy the private key to the server to test it?
No. Compare public fingerprints. The private key should remain at its approved client or hardware boundary.
Recovery
Rollback
Restore the backed-up authorization file and its original metadata from the open recovery session.
- Keep the fallback session open and restore `authorized_keys.before-oneliners` with `cp -a`.
- Restore documented owner and modes, run `sshd -t`, and repeat positive plus negative authentication tests.
- Remove the temporary backup only after the observation window and approval.
Evidence