Ubuntu VPS SSH Troubleshooting
Match your SSH error to the next check. Keep any working session open and choose the access you still have.
Find your next SSH check
Choose the failure and the access you still have. The result suggests checks; it does not inspect your server or establish a cause.
Browse all errors and access paths
First identify your access
A working SSH session
Keep that session open. Server checks may run there on the intended VPS; keep a separate recovery path before applying changes.
A logged-in console of the installed Ubuntu system
Confirm that the console is attached to this instance and its installed Ubuntu system. Run server checks there. A console login and public SSH use different paths.
Only a separate rescue system
A rescue system is not the running installed Ubuntu guest. systemctl and ss there describe the rescue environment. Use the provider recovery procedure to identify the correct disk; mounting it does not make its services run. Do not apply the live-server commands below to rescue.
No authenticated server access
Use client checks and the authenticated provider panel. Ask the provider or server administrator for guest-console/recovery access. Send the attempt time and timezone, instance identifier, port, error and last change; omit passwords, private keys and unredacted logs.
Then choose the error
Not sure where it fails
- Capture one fresh attempt and its exact final message. Keep any working session open.
- Compare the intended account, address, port and key with the client settings. Do not accept an unexplained host-key change.
With access to the running Ubuntu guest: Correlate the attempt time with the guest SSH journal; first establish the failure stage.
Capture and interpret one attempt →Connection timed out
- Identify whether debug output reached Connection established. A later timeout is not the same as failure to establish TCP.
- Compare the actual destination with the provider panel, including IPv4/IPv6, source-address restrictions and the required VPN or jump host.
With access to the running Ubuntu guest: Inspect the guest listener and firewall without resetting rules; correlate the attempt with logs.
Trace the network path →Connection refused
- Confirm the intended address and port. A refusal does not authenticate the destination.
- Check the instance state and provider network rules for that exact port and current source address.
With access to the running Ubuntu guest: Check the actual listening address/port and both ssh.service and ssh.socket.
Inspect the SSH listener →Permission denied (publickey)
- Confirm the account and which key fingerprint the client offered.
- Inspect IdentityFile and agent settings; retry with the intended existing key. Do not replace authorized keys to guess a fix.
With access to the running Ubuntu guest: Compare the offered fingerprint with the target account’s authorized keys and inspect the authentication log.
Check the account and key →REMOTE HOST IDENTIFICATION HAS CHANGED
- Stop before accepting the new identity. Confirm the instance and whether a rebuild or IP reassignment was expected.
- Obtain the guest host-key fingerprint through an independently trusted path. A key seen on the same unverified network connection is not independent verification.
With access to the running Ubuntu guest: Read the installed guest’s public host-key fingerprint and compare the same algorithm with the warning.
Verify the host identity →Could not resolve hostname / name differs from IP
- Check the exact hostname or SSH alias and its evaluated HostName. An alias can supply a different account, port or jump host.
- Compare name and IP attempts using the same user, port and key; inspect the resolved address and IPv4/IPv6 in debug output.
With access to the running Ubuntu guest: If the name reaches a different guest interface, compare its listener and network rules with the working path.
Check the name and address family →Local key unreadable / invalid format / bad permissions
- Check that -i points to the intended private-key file on this computer, not its public .pub file or a missing path.
- Inspect file access and format with the tools for your operating system. Keep the existing key and fix the specific read or format error.
With access to the running Ubuntu guest: Only after the local key loads, compare its offered identity with the authorized account key.
Check the local key file →Too many authentication failures
- Read which identities the client offered before disconnection; unrelated agent identities can consume attempts.
- Use the intended key with IdentitiesOnly=yes and inspect all configured IdentityFile entries.
With access to the running Ubuntu guest: Check the authentication log and applicable MaxAuthTries setting without raising limits as a shortcut.
Limit unintended identity attempts →kex / connection closed or reset before authentication
- Locate the last completed stage in a fresh debug attempt. Confirm whether it reached SSH negotiation or an explicit algorithm error.
- Confirm the destination and client version; check the provider network/security events around the same time.
With access to the running Ubuntu guest: Correlate the guest journal with the source and timestamp; investigate a logged rate limit or policy mismatch only when the evidence points there.
Investigate a pre-authentication disconnect →Authenticated, but shell / PTY / channel fails
- Confirm a completed Authenticated to message; Server accepts key alone is not completed authentication.
- Check whether the client requested a shell, command, SFTP or forwarding-only session. A restricted account may intentionally have no shell.
With access to the running Ubuntu guest: Match the session error to account policy, key restrictions, shell/home setup and relevant resource errors in the guest logs.
Investigate a session-stage failure →In this guide
Capture one failure and preserve working access
Keep any working session open. Client commands run on your computer; server commands require the running Ubuntu guest or its authenticated console. A separate rescue system is a different environment.
Use your existing private key. Replace the documentation address 203.0.113.10, account ubuntu, port 22 and key path before running an attempt. Stop at an unexplained host-key warning and use trusted identity verification.
Linux, macOS or WSL: inspect an existing connection
Run these in a local shell. ssh -V identifies the client; the file listing shows whether the selected private key exists and its permissions. Neither prints the private-key contents.
ssh -V
ssh_address='203.0.113.10'
ssh_user='ubuntu'
ssh_port='22'
ssh_key="$HOME/.ssh/ubuntu_vps"
ls -l "$ssh_key"
ssh -G -p "$ssh_port" -i "$ssh_key" "$ssh_user@$ssh_address"
date -u '+%Y-%m-%dT%H:%M:%SZ'
ssh -v -S none -o ConnectTimeout=10 -o StrictHostKeyChecking=ask -p "$ssh_port" -i "$ssh_key" "$ssh_user@$ssh_address"Optional direct TCP check, if your client already has netcat:
nc -vz -w 5 "$ssh_address" "$ssh_port"A successful TCP check only reaches a port. It does not verify SSH, the host identity or your login. For a jump-host route, this direct probe does not follow ProxyJump.
Windows PowerShell: inspect an existing connection
Use Windows OpenSSH Client. If Get-Command cannot find ssh, install the OpenSSH Client optional feature; a Windows SSH server is not needed to connect out. Run the following in PowerShell, not in the remote Ubuntu shell.
Get-Command ssh
ssh -V
$sshAddress = '203.0.113.10'
$sshUser = 'ubuntu'
$sshPort = 22
$sshKey = Join-Path $env:USERPROFILE '.ssh\ubuntu_vps'
Get-Item -LiteralPath $sshKey
Get-Acl -LiteralPath $sshKey | Format-List Owner,AccessToString
ssh -G -p $sshPort -i "$sshKey" "$sshUser@$sshAddress"
Test-NetConnection -ComputerName $sshAddress -Port $sshPort -InformationLevel Detailed
(Get-Date).ToUniversalTime().ToString('o')
ssh -v -S none -o ConnectTimeout=10 -o StrictHostKeyChecking=ask -p $sshPort -i "$sshKey" "$sshUser@$sshAddress"Check RemoteAddress and TcpTestSucceeded. True means TCP connected on that direct path; it is not a host-key or authentication check. A missing file or ACL error is local to Windows. Review the exact private file’s ownership/access; do not paste Linux chmod commands into PowerShell.
If your working client is PuTTY, its .ppk key is a different format. Use PuTTYgen locally to export an OpenSSH private key to a new protected file when switching clients. Preserve the original and never upload either private-key file.
Read the outcome before changing anything
ssh -Gprints evaluated client settings and exits; it does not prove that the server is reachable.- The debug attempt uses
-S noneto avoid reusing a shared connection. Record its UTC time, last completed stage and final message. Keep debug logs private or redact them before sharing. Connection establishedmeans the TCP stage completed. Host identity and user authentication still follow.- A new host-key prompt requires independent verification. A changed-key warning requires investigation before accepting a replacement.
Compare a working attempt with a failing one
Start with the same client, network, account, port and key; change only the hostname versus IP. Then compare ssh -G and debug output side by side:
- HostName, User and Port: does a Host alias change the destination or account?
- IdentityFile and IdentitiesOnly: which configured identities and offered fingerprints differ?
- ProxyJump / ProxyCommand: is one attempt indirect? Check that route instead of relying on a direct TCP probe.
- AddressFamily and the actual debug destination: are the attempts using different IPv4/IPv6 endpoints?
- HostKeyAlias and known-hosts files: do both attempts refer to the same verified host identity?
If only another computer or network works, keep the server settings unchanged while comparing client versions, configuration and source-address restrictions. Correct the observed difference, then repeat a fresh connection.
What the first error tells you
Timeout before TCP connects
The connection did not complete. Check the address and network path; the message does not identify one blocking rule.
Trace the path →Connection refused
The address and port actively rejected the attempt. Confirm the endpoint, listener and rejection rules.
Inspect the listener →Permission denied (publickey)
SSH reached authentication. Check the account, offered identity and applicable server policy.
Check the identity →Changed host identity
The presented key differs from a saved one. Verify the intended guest through a trusted path before proceeding.
Verify the server →If debug output reached Connection established before a timeout, investigate the later stage. See name, local-key, negotiation and session errors for the other branches.
Other messages: identify the failed stage
Could not resolve hostname, or IP works but the name fails
A name-resolution error happens before a direct TCP connection to the target. Correct a typo or missing SSH alias first. Inspect ssh -G: a Host block may select another username, key, port or ProxyJump, so “IP works” does not by itself prove broken DNS.
Compare the evaluated HostName and the actual address shown by debug output. If the hostname has both A and AAAA records, compare one ssh -4 and one ssh -6 attempt with the same account, port and key. IPv6 needs a working route, listener and rules of its own. With a jump host, name resolution and target connectivity can occur there; a local DNS check is not the complete path.
Next action: correct the one mismatched setting or stale record. Do not remove working IPv6 globally to conceal a different destination.
Identity file not accessible, invalid format or unprotected private key
These messages concern the client’s local key. Verify the full quoted path, filename and file owner. A private key is different from the public key uploaded to the provider. Never paste the private key into this page or support messages.
On Linux/macOS/WSL, inspect the file owner and mode with ls -l. For an ordinary private file you own, mode 600 restricts access to its owner; apply a permission change only to that verified file. Windows uses file ACLs instead of Bash permissions. If the format is invalid, check whether the file is truncated, a public key, or a PuTTY PPK file requiring local export to OpenSSH format. Preserve the original; changing the extension does not convert it.
Next action: retry after the key can be read. Do not regenerate keys or change the server’s authorized keys merely to suppress a local read error.
Too many authentication failures
The server ended the authentication attempts. An agent offering many unrelated keys is one possible cause, not a certainty. Inspect the offered fingerprints and use the existing-key attempt with IdentitiesOnly. Explicit IdentityFile entries can still add identities; inspect ssh -G as well.
With guest access: check the matching log entry and applicable MaxAuthTries policy. Avoid repeated retries or raising the limit before identifying the unwanted attempts.
kex_exchange_identification, reset or closed before authentication
A pre-authentication disconnect may come from the endpoint, a network intermediary or an admission rule. The text alone does not identify which. Capture the last debug lines and one timestamp. Confirm you are reaching SSH on the intended port, then correlate provider security events and the guest SSH journal if accessible.
If the error explicitly says no matching key-exchange, host-key or cipher algorithm, compare client/server versions and the applicable security policy. Prefer a supported compatible configuration. Do not universally enable obsolete algorithms. If logs instead identify a source block or connection limit, correct that specific condition; do not flush the firewall or disable protection globally.
Authenticated, then shell, PTY or channel request fails
An Authenticated to message places the failure after authentication. Server accepts key alone does not. First distinguish an interactive shell from SFTP, a remote command, port forwarding or ssh -N, which deliberately starts no remote command.
With guest access: inspect the matching session log and target account with getent passwd ubuntu (replace the username). Check its intended shell/home, applicable ForceCommand, PermitTTY and ChrootDirectory, and restrictions on the specific authorized key or certificate. A forwarding-channel failure needs its own forwarding/destination checks; it does not prove that login failed.
If the log reports a full filesystem, inode exhaustion or process/memory failure, inspect that resource with df -h, df -i, free -h and the relevant journal. These are observations, not proof of the cause. Fix the confirmed policy, path or resource condition without deleting data at random or removing deliberate account restrictions.
Timeout: trace the intended network path
Compare the destination shown by ssh -v with the current address in the provider panel. With a hostname, stale DNS or a different IPv6 destination can send the attempt elsewhere. Confirm whether this VPS requires a public address, VPN or jump host.
Check that the instance is running and its public routing is present. In the provider firewall, verify the actual SSH destination port and your current public source address. A home connection's address can change while a /32 allow rule stays unchanged. Check the guest firewall through the console as well.
On Oracle Cloud, security lists, NSGs, routing and the guest firewall all matter. Preserve the image's supplied firewall rules; installing UFW or flushing iptables is not a diagnostic step. The Oracle Ubuntu setup walkthrough explains that network layout. A failed ping alone does not prove SSH is unavailable.
Refused connection: inspect the listening service
A refusal does not authenticate the destination. Confirm the intended VPS and port. Run the checks below only through a working session or authenticated console of the running installed Ubuntu guest. In rescue or a chroot, service state and listeners do not represent that guest.
systemctl status ssh.service ssh.socket --no-pager
sudo ss -lntp
sudo /usr/sbin/sshd -tRead the result: find the actual listening address and port in ss. An inactive ssh.service can coexist with a listening ssh.socket. A missing unit needs investigation of the installed package/service, not an automatic reinstall. Silent success from sshd -t checks configuration and host keys; it does not prove that a port is listening or reachable.
Compare socket activation, unit overrides and running arguments
systemctl cat ssh.service ssh.socket --no-pager
systemctl show ssh.service -p ActiveState -p MainPID -p ExecStart -p FragmentPath -p DropInPaths -p NeedDaemonReload --no-pager
systemctl show ssh.socket -p ActiveState -p Listen -p FragmentPath -p DropInPaths -p NeedDaemonReload --no-pager
sudo ps -C sshd -o pid,ppid,argscat shows unit files and drop-ins on disk. show reports the manager’s loaded properties, including socket Listen and the configured service launch. NeedDaemonReload=yes indicates a unit-file change since loading; it is an observation, not a reason to reload blindly. Use MainPID and the process list to distinguish the daemon from connection processes. No running daemon at that instant can be normal with socket activation.
Ubuntu’s socket behavior has changed across releases; Ubuntu 24.04 introduced a generator that reads Port and ListenAddress. Determine the actual mode and overrides on this machine. The distribution version or an edited Port line alone does not establish the current listener. Compare the loaded unit, any launch-time -f/-o/-p options and ss before planning a correction.
Evaluate settings for the actual user and source
sshd -T prints the parsed effective configuration; -C supplies a connection context for applicable Match rules. This example uses the default configuration. If the actual launch selects another file or overrides settings, include those configuration options in the test too. Do not copy daemon-start flags such as -D into this inspection.
Replace all example values with what sshd sees: user is the target account; addr is the connecting source address (possibly a jump host/NAT); host is the resolved source hostname, not the VPS hostname; laddr and lport are the guest-side destination. Behind NAT, laddr can be private. When source-name lookup is not used, use the numeric source value; do not invent a reverse hostname.
check_user='ubuntu'
check_source='198.51.100.25'
check_source_name='198.51.100.25'
check_local='10.0.0.5'
check_port='22'
sudo /usr/sbin/sshd -T -C "user=$check_user,addr=$check_source,host=$check_source_name,laddr=$check_local,lport=$check_port"Inspect PubkeyAuthentication, AuthenticationMethods, AuthorizedKeysFile/AuthorizedKeysCommand, AllowUsers/DenyUsers, group rules, ForceCommand and PermitTTY as relevant. Resolve relative authorized-key paths against the account’s actual home from getent passwd. Provider-managed key commands or certificate policy may replace the simple file-based route.
Ubuntu normally includes sshd_config.d snippets near the start of sshd_config. Many settings use the first obtained value, and conditional Match rules need the correct context. Adding a later duplicate line may not change the effective result. Review the applicable file/rule instead of disabling StrictModes or account restrictions.
The test reads configuration now; it cannot prove what a daemon loaded earlier, whether authentication will pass, or what systemd is currently listening on. Keep the listener and log checks separate.
Match the journal to one failed attempt
Record the client attempt in UTC, check the guest clock, and replace both example endpoints below with a short window around that attempt:
date -u '+%Y-%m-%dT%H:%M:%SZ'
sudo journalctl -u ssh.service -u ssh.socket --since '2026-10-13 12:00:00 UTC' --until '2026-10-13 12:02:00 UTC' --utc -o short-iso-precise --no-pagerMatch the time, source and account, then distinguish negotiation, authentication and session messages. If your service uses another unit or logging destination, inspect that configured destination. No entry can mean the request never arrived, but also different logging, insufficient permissions, clock mismatch or expired records; it does not prove a firewall cause.
Before applying a correction: preserve independent access, validate the matching configuration, follow the active service/socket mode and then prove a fresh login. Changing a port may also require narrow provider and guest rules. These inspection commands deliberately do not restart services or rewrite firewall policy.
Rejected public key: check the account and offered identity
Use the provider's initial account or an administrator you created, not a guessed username. In client debug output, find which key fingerprint was offered. To reduce unrelated keys offered by an agent, retry locally with:
ssh -v -S none -o IdentitiesOnly=yes -o StrictHostKeyChecking=ask -p 22 -i ~/.ssh/ubuntu_vps ubuntu@203.0.113.10Configured IdentityFile entries can still apply; inspect ssh -G. If the client reports an unreadable key or overly permissive private-key file, correct access to that local file before changing the server.
On the server, inspect the target account and its authorized public keys. This example assumes its home is /home/ubuntu; substitute the home returned by getent:
getent passwd ubuntu
sudo ls -ld /home/ubuntu /home/ubuntu/.ssh /home/ubuntu/.ssh/authorized_keys
sudo ssh-keygen -lf /home/ubuntu/.ssh/authorized_keysCompare the authorized fingerprints with the offered one. Inspect the journal for ownership, permission or account-policy failures. Check configured AuthorizedKeysFile, included snippets and Match rules when the default path is not used. Provider-managed key services can also change the mechanism. Preserve existing authorized keys; do not disable StrictModes or enable passwords to hide the cause.
Changed host identity: verify before reconnecting
A rebuild or reassigned IP can change the host key, but an unexpected change can also indicate the wrong endpoint or an interception. Confirm the instance identifier and any planned rebuild through your authenticated provider panel.
Through trusted console access to the guest, inspect the public host key matching the algorithm shown by your client. For an Ed25519 host key:
sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub -E sha256Compare its SHA256 fingerprint with the client warning. This is the server key, not your login key or the provider console gateway's key. A verified replacement may require updating that server's saved host entry; back up the file and preserve unrelated entries. Do not delete known_hosts wholesale or bypass checking. If identity remains unexplained, stop the connection and investigate.
After verification: update the specific saved record
Continue only after an independently trusted guest-console fingerprint matches the replacement key and the identity change is explained. If you only have an unverified network fingerprint, stop here.
- Identify the lookup and file. Use the same
ssh -Ginvocation as the failed attempt. Inspect HostName, Port, HostKeyAlias, UserKnownHostsFile and GlobalKnownHostsFile; read the exact offending file/line in the warning. A custom HostKeyAlias, multiple files, a KnownHostsCommand or a host certificate can change this path. For a managed trust file or CA/revocation policy, ask its administrator instead of removing a record. - Find the affected entries. For an ordinary port-22 lookup use the exact hostname or IP stored for that connection. For a non-default port without an alias, the usual lookup is
[hostname]:port, for example[203.0.113.10]:2222. Confirm it against the warning/configuration; do not guess an alias.
Linux/macOS/WSL: search and back up the selected file
Replace these defaults with the verified file and lookup. -F also finds hashed entries; -l displays fingerprints.
known_file="$HOME/.ssh/known_hosts"
known_name='203.0.113.10'
ssh-keygen -F "$known_name" -f "$known_file" -l
known_backup=$(mktemp "$known_file.backup.XXXXXX") &&
cp -p "$known_file" "$known_backup" &&
printf 'Backup saved: %s\n' "$known_backup"Continue only if the search identifies the affected record and the backup succeeds. Keep the printed backup path.
Windows PowerShell: search and back up the selected file
$knownFile = Join-Path $env:USERPROFILE '.ssh\known_hosts'
$knownName = '203.0.113.10'
ssh-keygen -F "$knownName" -f "$knownFile" -l
$knownBackup = $knownFile + '.backup.' + [guid]::NewGuid().ToString('N')
Copy-Item -LiteralPath $knownFile -Destination $knownBackup -ErrorAction Stop
Get-Item -LiteralPath $knownBackupUse the actual path and lookup from your warning. Continue only after finding the record and confirming a successful backup.
- Edit only the confirmed obsolete binding. Open that local file in a text editor. Match its reported line, host field, key algorithm and old fingerprint. Remove the obsolete line only if it belongs solely to this lookup. Preserve other algorithms and other hosts; if a line lists several names, edit only the obsolete host binding or ask an administrator. Search again with
-Fto review what remains. Do not delete the entire known_hosts file or run a blanket removal for all matching algorithms. - Make a fresh connection. Repeat your original
ssh -v -S none -o StrictHostKeyChecking=askattempt with the same account, destination, port and key. If asked to accept a key, compare its algorithm and SHA256 fingerprint again with the independently verified value before answering yes. If it differs or another warning appears, stop and investigate that record separately. - Verify the result. Confirm the expected account opens in the new session and retain the backup until the change is verified.
ssh-keyscanalone cannot establish trust in a replacement key; disabling host-key checking is not a verification step.
Validate the specific correction in a fresh session
Correct the identified address, user, key, narrow network rule or configuration error. Preserve an independent access path during server changes and validate SSH configuration before applying them. A new port may also involve socket activation settings, not just a service restart.
Repeat the original attempt with connection sharing disabled. Confirm a fresh login reaches the expected account and that required sudo access works. An old session staying connected is not this test. Record what failed and what changed. Then return to the Ubuntu VPS deployment guide if setup was interrupted.
Save the incident and the result
Keep a short record of one SSH failure for yourself or support. These are your observations, not an automatic server inspection. Enter summaries, not passwords, private keys or complete debug logs.
A working old session is not a fresh-login test. Before closing the case, confirm the expected account and any required sudo access using a new connection, and resolve the remaining issues you recorded.
Questions and answers
Should I reinstall Ubuntu to fix SSH?
Diagnose first. A wrong address, username or key does not require reinstalling the operating system, and reinstalling can destroy data. Use the provider's recovery process when no access remains.
Does a working console prove SSH should work?
No. Console access and public SSH use different paths. The guest listener, account authentication and network rules still need to permit the SSH connection.
Sources and verification
- Ubuntu OpenSSH server documentation
- OpenSSH client manual
- OpenSSH client configuration manual
- OpenSSH server test modes
- OpenSSH server configuration manual
- OpenSSH key fingerprint tools
- Ubuntu 24.04 OpenSSH socket activation
- Oracle image firewall requirements
Additional references reviewed on 13 October 2026: Microsoft OpenSSH Client and Test-NetConnection documentation; systemd 255 systemctl, journalctl and unit-property manuals. Check the manuals for the versions installed on your own system.