SSH VPN tutorial

SSH Connection Troubleshooting Guide

16 min read
ssh command line tutorial

In the intricate tapestry of modern digital infrastructure, Secure Shell (SSH) stands as a foundational pillar, enabling secure remote access, file transfers, and command execution across interconnected systems. Its ubiquity, however, belies a potential for frustration when the seemingly straightforward act of connecting encounters an unforeseen impediment. For IT professionals, developers, system administrators, and even advanced users, an unresponsive SSH connection can halt critical operations, making the ability to diagnose and resolve these issues not just a skill, but a necessity.

This exhaustive guide is engineered to demystify the complexities of SSH connection failures. Moving beyond superficial checks, we delve into the architectural nuances of the SSH protocol, providing a systematic, step-by-step diagnostic framework. From the most common client-side misconfigurations to intricate server-side permissions, network obstructions, and advanced protocol discrepancies, this article aims to equip you with the knowledge and tools to effectively troubleshoot and restore your SSH connectivity with confidence and precision.

The Foundational Handshake: Understanding SSH Connections

Before embarking on troubleshooting, a brief understanding of the SSH connection process can illuminate potential points of failure. When an SSH client attempts to connect to a server, a multi-stage handshake occurs:

1. TCP Connection: The client initiates a standard TCP/IP connection to the server’s SSH port (default 22).
2. Protocol Version Exchange: Client and server exchange their supported SSH protocol versions.
3. Algorithm Negotiation: They agree on cryptographic algorithms for encryption, key exchange, and integrity checking.
4. Host Key Verification: The server presents its public host key. The client checks this against its `known_hosts` file to verify the server’s identity.
5. Authentication: The client attempts to authenticate itself to the server using methods like password, public key, or other schemes.
6. Session Establishment: Upon successful authentication, a secure, encrypted channel is established, allowing for command execution and data transfer.

Failure at any of these stages can prevent a successful connection. Our troubleshooting methodology will dissect these stages to pinpoint the exact point of divergence.

Initial Triage: The Fundamental Checks

Before diving into complex diagnostics, always begin with a series of basic checks. Many SSH issues stem from simple oversights.

Verifying Network Connectivity

The most rudimentary yet critical step is to confirm that your client machine can even reach the target server at a network level.

Using `ping`

`ping `

  • Expected: Continuous replies, indicating network reachability.
  • Issue: “Request timed out,” “Destination Host Unreachable,” or similar errors suggest a fundamental network problem, not an SSH-specific one.
  • Action: Check your local network connection, router status, and ensure the server is powered on and configured with a valid IP.

Using `traceroute` (or `tracert` on Windows)

`traceroute `

  • Purpose: Identifies the path packets take to reach the server and can pinpoint where connectivity breaks down (e.g., a specific router or firewall blocking the path).
  • Expected: A sequence of hops reaching the destination.
  • Issue: Hops timing out repeatedly at a specific point might indicate a firewall blocking ICMP or an unreachable network segment.

Testing Port Reachability with `nc` or `telnet`

`nc -vz 22` (Linux/macOS)
`telnet 22` (Windows/Linux/macOS – may need installation)

  • Purpose: Directly tests if a TCP connection can be established to the SSH port (default 22) on the server. This bypasses the SSH protocol itself, testing only the underlying TCP layer.
  • Expected:
  • `nc`: “Connection to 22 port [tcp/ssh] succeeded!”
  • `telnet`: A blank screen or “SSH-2.0-OpenSSH_…” banner, indicating a successful TCP handshake.
  • Issue: “Connection refused,” “No route to host,” or timing out suggests a firewall (client-side, server-side, or intermediate) is blocking the port, or the SSH daemon isn’t running on the server.

Correct SSH Client Syntax

Even experienced users can make typos. Double-check your SSH command.

`ssh [options] [username]@[server_ip_address_or_hostname] -p [port_number]`

  • Common Mistakes:
  • Incorrect username.
  • Wrong IP address or hostname.
  • Forgetting `-p` if the SSH server uses a non-standard port.
  • Incorrect key file specified (`-i /path/to/key.pem`).

User Permissions (Local Client)

Ensure the current user on your client machine has the necessary permissions to read private keys (if using key-based authentication) and execute the `ssh` command.

  • Key files *must* have restricted permissions: `chmod 400 ~/.ssh/id_rsa` or `chmod 600 ~/.ssh/id_rsa`. If permissions are too open, SSH will often refuse to use the key.

Client-Side Troubleshooting: Diagnosing Issues on Your Machine

Many SSH problems originate from the client-side configuration or environment.

Leveraging Verbose Output

The single most powerful client-side troubleshooting tool is the verbose flag (`-v`, `-vv`, `-vvv`).

`ssh -v user@server`
`ssh -vv user@server`
`ssh -vvv user@server`

  • Purpose: Each additional `v` increases the verbosity, providing detailed output on the client’s connection attempt, algorithm negotiation, authentication process, and potential errors.
  • Interpretation: Look for messages like:
  • `debug1: Connecting to …`: Indicates initial connection attempt.
  • `debug1: Connection established.`: TCP connection is good.
  • `debug1: SSH2_MSG_KEXINIT sent`: Key exchange is starting.
  • `debug1: Authentications that can continue: publickey,password`: Server’s allowed authentication methods.
  • `debug1: Offering public key: …`: Client is trying a key.
  • `debug1: Server accepts key: …`: Key accepted.
  • `Permission denied (publickey,password).`: Indicates authentication failure.

Checking SSH Client Configuration (`~/.ssh/config`)

The `~/.ssh/config` file allows you to define aliases and specific configurations for different hosts. Misconfigurations here can lead to unexpected behavior.

`cat ~/.ssh/config`

  • Look for:
  • `HostName`: Is it correct?
  • `User`: Is the correct username specified?
  • `Port`: Is the correct port specified? (This overrides the default 22).
  • `IdentityFile`: Is the path to your private key correct?
  • `IdentitiesOnly yes`: Can sometimes cause issues if you expect SSH to try multiple keys.
  • Action: Temporarily comment out (`#`) or remove specific host entries to see if the issue resolves, then re-add them carefully.

Issues with Key-Based Authentication

Public-key authentication is the most secure and common method, but it’s also a frequent source of troubleshooting headaches.

Incorrect Private Key Path

  • Symptom: `Permission denied (publickey).` even when you’re sure the key is correct.
  • Action: Ensure you’re specifying the correct private key file using the `-i` flag: `ssh -i /path/to/your/key.pem user@server`.

Incorrect Key Permissions (Client-Side)

  • Symptom: `Permissions for ‘key.pem’ are too open.`
  • Action: Private key files *must* have restricted permissions.

`chmod 400 ~/.ssh/id_rsa` (read-only for owner)
`chmod 600 ~/.ssh/id_rsa` (read/write for owner)
The specific permission `400` is often preferred for private keys.

Wrong Key for the Server

  • Symptom: `Permission denied (publickey).`
  • Action: Ensure the public key corresponding to your private key is installed on the server in the `~/.ssh/authorized_keys` file for the correct user.

Passphrase Issues

  • Symptom: Prompted for a passphrase, but it’s rejected.
  • Action: Double-check your passphrase. If you forget it, there’s no recovery for the key itself, but you can generate a new key pair. Consider using `ssh-agent` to manage your keys and avoid repeated passphrase entry.

`known_hosts` File Issues

The `~/.ssh/known_hosts` file stores the public host keys of servers you’ve connected to.

Host Key Mismatch Warning

  • Symptom: `WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!` This usually happens if the server’s SSH host key has legitimately changed (e.g., server rebuilt, IP reassigned to a new server) or, more alarmingly, if there’s a Man-in-the-Middle (MITM) attack.
  • Action:

1. Verify Legitimacy: If you expect the change, confirm the new fingerprint with the server administrator through an out-of-band channel.
2. Remove Old Entry: Use `ssh-keygen -R ` to remove the old entry from your `known_hosts` file.
3. Reconnect: The new host key will be added on your next successful connection.

Corruption or Permissions

  • Symptom: Various obscure errors related to host key verification.
  • Action: Check permissions: `chmod 600 ~/.ssh/known_hosts`. If still problematic, try temporarily moving or backing up the file and letting SSH recreate it, though this is less common.

Server-Side Troubleshooting: Investigating the Remote Machine

If client-side checks yield no solutions, the problem likely resides on the server. This often requires console access or an alternative way to log in (e.g., cloud provider’s web console, physical access).

SSH Daemon Status

The SSH server daemon (`sshd`) must be running and listening for connections.

Checking Service Status

`sudo systemctl status sshd` (on systems using systemd, like modern Ubuntu, CentOS, Debian)
`sudo service sshd status` (older systems or SysVinit)

  • Expected: “active (running)”
  • Issue: “inactive (dead)”, “failed”, or “not found”.
  • Action: Start the service: `sudo systemctl start sshd` or `sudo service sshd start`.
  • Action: Enable it to start on boot: `sudo systemctl enable sshd`.

Checking Listening Port

`sudo netstat -tuln | grep 22` (or your custom SSH port)
`sudo ss -tuln | grep 22` (modern alternative to netstat)

  • Expected: Output showing `tcp` listening on port `0.0.0.0:22` (all interfaces) or a specific IP address.
  • Issue: No output, or it’s listening on the wrong interface/port.
  • Action: This indicates `sshd` isn’t running, or it’s configured to listen on a different port or interface. Check `sshd_config`.

Server Firewall Configuration

Firewalls are a leading cause of connection issues. Even if `sshd` is running, a firewall might be blocking incoming connections.

Common Firewall Systems

##### UFW (Uncomplicated Firewall – Ubuntu/Debian)

`sudo ufw status verbose`

  • Expected: Rule allowing traffic on port 22 (or your custom SSH port). Example: `22/tcp ALLOW IN Anywhere`.
  • Issue: No rule for SSH, or a rule explicitly denying it.
  • Action: `sudo ufw allow 22/tcp` (or `sudo ufw allow /tcp`).
  • Action: `sudo ufw enable` (if not already enabled, proceed with caution as this will apply firewall rules).

##### Firewalld (CentOS/RHEL 7+)

`sudo firewall-cmd –list-all`

  • Expected: `services: ssh` or `ports: 22/tcp` listed in the active zone.
  • Issue: SSH service not listed.
  • Action: `sudo firewall-cmd –zone=public –add-service=ssh –permanent`
  • Action: `sudo firewall-cmd –reload`

##### iptables (Generic Linux)

`sudo iptables -nvL`

  • Expected: A rule in the `INPUT` chain accepting TCP traffic on port 22 (or your custom port). Example: `-A INPUT -p tcp –dport 22 -j ACCEPT`.
  • Issue: No such rule, or a `DROP` rule overriding it.
  • Action: Adding `iptables` rules can be complex and requires care. It’s often safer to use a higher-level tool like UFW or Firewalld if available. If directly editing, ensure you save rules persistently after adding: `sudo apt-get install iptables-persistent` or `sudo service iptables save`.

SSH Server Configuration (`/etc/ssh/sshd_config`)

This is the primary configuration file for the SSH daemon. Incorrect settings here can prevent connections. Always back up this file before making changes: `sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak`. After modifying, restart `sshd` for changes to take effect: `sudo systemctl restart sshd`.

Key Parameters to Check:

  • `Port 22`: Ensure this matches the port you’re trying to connect to. If it’s commented out (`#`), it defaults to 22.
  • `ListenAddress 0.0.0.0`: This ensures `sshd` listens on all available network interfaces. If it’s set to a specific IP, ensure that IP is correct and reachable.
  • `PermitRootLogin yes` / `no` / `prohibit-password`: If you’re trying to log in as `root`, ensure this is `yes` or `prohibit-password` (if using keys). `no` is a security best practice.
  • `PasswordAuthentication yes` / `no`: If you’re trying to use a password and it’s failing, ensure this is set to `yes`. If `no`, only key-based authentication is allowed.
  • `PubkeyAuthentication yes`: Essential if you’re using SSH keys.
  • `AllowUsers`, `DenyUsers`, `AllowGroups`, `DenyGroups`: These directives restrict which users or groups can log in via SSH. Ensure your user is not explicitly denied or excluded.
  • `AuthenticationMethods`: If specified, ensure your desired method (e.g., `publickey`) is listed.
  • `MaxAuthTries`: If set too low, repeated failed attempts might temporarily block a user.
  • `Protocol 2`: Ensure only Protocol 2 is enabled (default). Protocol 1 is insecure.
  • `UsePAM yes`: If `PAM` (Pluggable Authentication Modules) is used for authentication, ensure this is enabled.
  • `ChallengeResponseAuthentication no`: Usually set to `no` for security reasons, unless explicitly using methods like Google Authenticator.

Syntax Errors in `sshd_config`

  • Symptom: `sshd` fails to start or restart without clear errors.
  • Action: Run `sudo sshd -t` to test the configuration file for syntax errors without restarting the service.

User Permissions (Server-Side)

Even with correct `sshd_config` settings, incorrect file permissions on the server can prevent authentication.

Home Directory Permissions

  • Issue: A user’s home directory (`/home/username`) or the `~/.ssh` directory has incorrect permissions.
  • Action:
  • `chmod 755 /home/username` (or `700` for stricter security)
  • `chmod 700 /home/username/.ssh`
  • `chmod 600 /home/username/.ssh/authorized_keys`
  • Ownership: Ensure the user’s home directory and `.ssh` directory are owned by the user: `sudo chown -R username:username /home/username`.

`authorized_keys` File

  • Issue: The public key for your client is not in `~/.ssh/authorized_keys` on the server for the correct user, or the file is malformed.
  • Action: Verify the content of `~/.ssh/authorized_keys`. Each public key should be on a single line. Ensure there are no extra spaces or line breaks.
  • Action: Make sure the public key on the server corresponds to the private key you’re using on the client.

Checking Server Logs

Server logs are invaluable for pinpointing authentication and connection issues.

`sudo tail -f /var/log/auth.log` (Debian/Ubuntu)
`sudo tail -f /var/log/secure` (CentOS/RHEL)
`sudo journalctl -u sshd -f` (systemd systems)

  • Look for:
  • `Failed password for …`
  • `Authentication refused: bad ownership or modes for directory …`
  • `User XXX from YYY not allowed because listed in DenyUsers`
  • `fatal: Timeout before authentication for …`
  • `Invalid user …`
  • Action: The log messages are often very specific and directly point to the cause (e.g., wrong password, permission issues, user not allowed).

SELinux or AppArmor

Security modules like SELinux (CentOS/RHEL) or AppArmor (Ubuntu) can impose additional restrictions that might prevent SSH from functioning correctly, even if other configurations appear sound.

SELinux

`sestatus` (checks if SELinux is enforcing)
`sudo ausearch -c sshd –raw | audit2allow -M my-sshd` (identifies and suggests policy changes)

  • Symptom: `Permission denied` errors in `/var/log/audit/audit.log` or generic SSH failures despite correct permissions and configuration.
  • Action: Temporarily set SELinux to `permissive` mode (`sudo setenforce 0`) to see if the issue resolves. If it does, you’ll need to create a custom SELinux policy or adjust existing ones rather than permanently disabling it.

AppArmor

`sudo aa-status`

  • Symptom: Similar to SELinux, it might block `sshd` from accessing certain files or network ports.
  • Action: Check `/var/log/kern.log` or `/var/log/syslog` for AppArmor denied messages related to `sshd`. Temporarily disable AppArmor for `sshd` to diagnose, but re-enable with proper configuration.

Server Resource Exhaustion

An overloaded server can manifest as SSH connection timeouts or rejections.

  • Symptoms: Very slow or unresponsive connections, `Connection refused` after a long delay, even if `sshd` appears running.
  • Action:
  • Check CPU, memory, and disk I/O using tools like `top`, `htop`, `free -h`, `df -h` (if you can get in via console or web interface).
  • Restart the server if it’s completely unresponsive and other options fail.
  • Investigate running processes to identify resource hogs.

Network-Level Troubleshooting: Beyond Client and Server

Sometimes the problem isn’t with your machine or the server, but somewhere in between.

Intermediate Firewalls

Corporate networks, cloud providers, and even home routers often have firewalls that can block SSH traffic.

Cloud Security Groups/Network ACLs

  • AWS Security Groups, Azure Network Security Groups, Google Cloud Firewall Rules: These are common external firewalls that filter traffic *before* it reaches your server.
  • Action: Log into your cloud provider’s console and verify that your client IP address (or `0.0.0.0/0` for testing, though not recommended for production) is explicitly allowed on port 22 (or your custom port) for the server’s instance.

Corporate/Home Router Firewalls

  • Symptom: Connections fail when trying to connect from specific networks.
  • Action: If connecting from a corporate network, consult with your network administrator. If from a home network, check your router’s firewall settings and ensure no port forwarding rules are inadvertently sending SSH traffic elsewhere.

DNS Resolution Issues

If you’re connecting via a hostname, DNS resolution must be working correctly.

  • Symptom: `ssh: Could not resolve hostname : Name or service not known`
  • Action:
  • Try connecting using the server’s IP address directly. If this works, the problem is DNS-related.
  • Check your client’s DNS configuration (e.g., `/etc/resolv.conf`).
  • Check if the server’s DNS records are correct.

Advanced Scenarios and Less Common Issues

For persistent or unique problems, consider these less frequent causes.

Mismatched Protocol Versions

While modern SSH clients and servers universally support SSH Protocol 2, very old or highly specialized systems might have issues.

  • Symptom: Connection fails early in the handshake, often with cryptic protocol-related errors.
  • Action: Ensure both client and server are using SSH Protocol 2. In `sshd_config`, `Protocol 2` should be set.

Ephemeral Port Exhaustion (Client-Side)

On systems with many simultaneous outbound connections, the client might run out of ephemeral (source) ports.

  • Symptom: Sporadic `Connection refused` or `Connection timed out` errors, especially under heavy load.
  • Action: While rare for typical SSH use, increase the range of ephemeral ports or decrease TCP timeout settings on the client if this is suspected.

Time Skew

Significant time differences between client and server can sometimes interfere with authentication mechanisms, especially those relying on timestamps or Kerberos.

  • Action: Ensure both client and server clocks are synchronized (e.g., using NTP).

Server Key Changes After VM Migration/Snapshot

If a VM is migrated or restored from a snapshot, its host key might change, leading to `REMOTE HOST IDENTIFICATION HAS CHANGED!` warnings on subsequent client connections.

  • Action: Treat this like any other `known_hosts` mismatch, verifying the legitimacy and then removing the old key entry on the client.

Troubleshooting via a Jump Host (Bastion Host)

If you can only reach your target server through an intermediate “jump host,” troubleshoot the connection to the jump host first. Once connected to the jump host, you can then try to SSH from there to your target, which might provide different error messages.

  • Command: `ssh -J user@jump_host user@target_host`
  • Action: If direct connection to the target fails, try connecting to the jump host and then using `ssh user@target_host` from within the jump host. This isolates whether the issue is between your client and the jump host, or between the jump host and the target.

Best Practices for Preventing SSH Issues

A proactive approach can significantly reduce the frequency of SSH connection problems.

1. Regular Updates: Keep your SSH client and server software updated to patch vulnerabilities and ensure compatibility.
2. Consistent Configuration Management: Use tools like Ansible, Puppet, or Chef to manage `sshd_config` and `authorized_keys` files across your servers. This reduces manual errors.
3. Use SSH Keys: Always prefer public-key authentication over passwords. Keys are more secure and can be managed more effectively.
4. Strong Passphrases: Protect your private keys with strong, unique passphrases.
5. Audit Logs Regularly: Periodically review SSH logs (`auth.log`/`secure`) for suspicious activity or recurring errors that might indicate an underlying issue.
6. Backup Configurations: Before making any changes to `sshd_config` or firewall rules, always back up the original files.
7. Limit Root Login: Disable direct root login via SSH (`PermitRootLogin no` or `prohibit-password`) and use `sudo` for administrative tasks.
8. Non-Standard Port: Consider changing the SSH port from the default 22 to a non-standard port to reduce automated attack attempts (though this is security by obscurity, it helps with noise).

Conclusion

Troubleshooting SSH connection issues, while often daunting, becomes a manageable process when approached systematically. By understanding the underlying SSH handshake, meticulously examining client-side configurations, thoroughly inspecting server-side daemons and firewalls, and considering intermediate network obstructions, you can effectively diagnose and rectify most connectivity problems. The key lies in methodical elimination: start with the basics, leverage verbose output, consult server logs, and isolate the layer at which the connection is failing. With this comprehensive guide, the labyrinth of SSH errors transforms into a clear, navigable path towards robust and secure remote access.