ThisCalculator

Everyday

Fix SSH Port Forwarding Failures to a Remote Database

Updated · Standard formula, shown below

Fix SSH Port Forwarding Failures to a Remote Database

SSH port forwarding lets you securely connect to a remote database that isn’t directly exposed to the internet, by tunneling the connection through an SSH server. When it fails, you can’t reach the database, and the error messages are often cryptic. This guide walks you through the most common causes—wrong flags, binding issues, firewall blocks, and authentication problems—and shows you how to fix each one.

What You’ll Need

  • SSH client (OpenSSH is standard on Linux, macOS, and Windows 10+).
  • SSH credentials (username and password or key) for the SSH server.
  • Network access to the SSH server (usually port 22, but could be custom).
  • Database connection details: host, port, and credentials for the database itself.
  • Ability to run commands in a terminal or command prompt.

Step-by-Step

  1. Verify the basic SSH connection. Before dealing with forwarding, ensure you can SSH into the server normally: ssh user@ssh-server. If this fails, fix the SSH connection first (check hostname, port, credentials, and firewall).
  2. Confirm the database is reachable from the SSH server. Log into the SSH server and try connecting to the database from there using its local tools (e.g., mysql -h db-host -P 3306). If that fails, the database is down, unreachable from the server, or the host/port are wrong. Fix that before proceeding.
  3. Use the correct forwarding syntax. For local forwarding (the most common for databases), the syntax is: ssh -L local_port:db_host:db_port user@ssh-server. For example, to forward local port 3306 to a database at db.internal on port 3306: ssh -L 3306:db.internal:3306 user@ssh-server. Make sure you don’t mix up the order—the first port is your local port, then the target host and port as seen from the SSH server.
  4. Check for local port conflicts. If the local port is already in use, SSH will fail with “bind: Address already in use.” Choose a different local port, e.g., ssh -L 3307:db.internal:3306 ..., and then connect your database client to localhost:3307.
  5. Add the -N flag if you don’t need a shell. If you only want the tunnel and don’t need an interactive SSH session, use ssh -N -L .... This prevents the tunnel from closing when you exit the shell.
  6. Use -f to background the tunnel. Add -f to run SSH in the background after authentication: ssh -f -N -L 3306:db.internal:3306 user@ssh-server. This frees your terminal. To stop the tunnel later, find the process with ps aux | grep ssh and kill it.
  7. Test the tunnel. In a new terminal, try connecting to the database using the local port, e.g., mysql -h 127.0.0.1 -P 3306 -u dbuser -p. If that works, you’re done.
  8. If using a key, ensure it’s loaded. If you use SSH keys, make sure the private key is available and the public key is installed on the server. Test with ssh -i /path/to/key user@ssh-server first.
  9. Check SSH server config for AllowTcpForwarding. On the SSH server, the file /etc/ssh/sshd_config must have AllowTcpForwarding yes (it’s usually yes by default). If it’s set to no, the server will reject forwarding attempts. You’ll need admin access to change it and restart sshd.
  10. Try verbose mode for diagnostics. Run ssh -v -L ... to see detailed logs. Look for lines like “Local forwarding listening on …” or error messages that point to the exact failure.

Common Mistakes

  • Using the wrong host in the forwarding spec. The db_host must be resolvable from the SSH server, not from your local machine. If the database is on the same server as SSH, use localhost or 127.0.0.1.
  • Forgetting to specify the database port. If the database runs on a non-default port, you must include it. For example, PostgreSQL often uses 5432, not 3306.
  • Connecting to the wrong local port. After setting up the tunnel, your database client must connect to localhost (or 127.0.0.1) and the local port you chose, not the remote host/port.
  • Not using -N and then closing the terminal. If you close the SSH session, the tunnel dies. Use -N and -f to keep it alive in the background.
  • Firewall blocking the SSH port. Even if SSH works from your network, some firewalls block port 22. Test with a different port if needed.

Tips

  • Use -C to enable compression if you’re transferring large amounts of data over a slow link.
  • For repeated use, create an SSH config entry in ~/.ssh/config with the LocalForward directive. Example: Host tunnel
    HostName ssh-server
    User youruser
    LocalForward 3306 db.internal:3306
    then simply run ssh tunnel.
  • If the database is on the same machine as the SSH server, use localhost as the target host to avoid DNS issues.
  • Use ssh -L 0.0.0.0:3306:db.internal:3306 to allow other machines on your local network to use the tunnel (bind to all interfaces). Be careful with security.
  • If you need to forward multiple ports (e.g., for multiple databases), use multiple -L flags in one command.

Troubleshooting

“bind: Address already in use” — The local port is taken. Choose a different local port or kill the process using it.

“Permission denied (publickey)” — Authentication failed. Check your username, key path, or try password authentication. If the server only allows keys, make sure your public key is in ~/.ssh/authorized_keys on the server.

“channel 1: open failed: connect failed” — The SSH server cannot connect to the target host/port. Verify the target host is reachable from the SSH server (try telnet db_host db_port from the server). Also check that the database is listening on that port.

“Warning: remote port forwarding failed for listen port” — This happens with remote forwarding (-R). Usually the remote port is already in use or the server has GatewayPorts disabled. For local forwarding, this message is rare.

Tunnel establishes but database connection times out — The database client may be trying to connect to a different host. Make sure you’re connecting to 127.0.0.1 (not localhost if IPv6 is an issue) and the correct port. Also check if the database server is bound to a specific interface and not accepting connections from the SSH server’s localhost.

SSH connection drops after a while — Add ServerAliveInterval 60 to your SSH command or config to keep the connection alive.

Frequently Asked Questions

Q: What’s the difference between local and remote forwarding?
A: Local forwarding (-L) forwards a port on your local machine to a remote destination. Remote forwarding (-R) forwards a port on the SSH server to a local destination. For accessing a remote database, you almost always want local forwarding.

Q: Can I use SSH port forwarding to access a database over the internet without exposing it?
A: Yes, that’s the main purpose. The database stays behind a firewall, and only the SSH server is exposed. The tunnel encrypts the connection.

Q: How do I stop a background SSH tunnel?
A: Find the process ID with ps aux | grep "ssh -f" and kill it with kill PID. Or use pkill -f "ssh -f -N -L" to kill all matching processes.

Q: Why does my tunnel work from the command line but not from a script?
A: Scripts often run in a non-interactive shell without the SSH agent loaded. Ensure the key is loaded (e.g., ssh-add) or use a key file path with -i.

Q: Can I forward a Unix socket instead of a TCP port?
A: Yes, OpenSSH supports forwarding Unix sockets with -L /local/socket:/remote/socket (with a special syntax). This is less common for databases but possible.

Q: Is it safe to use SSH port forwarding for a production database?
A: Yes, it’s secure because the data is encrypted. However, ensure the SSH server is hardened and the tunnel is only accessible to authorized users. Avoid binding to 0.0.0.0 unless necessary.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.