Blog

SSH tunnel is open, yet 'channel open failed: Connection refused'

This error does not come from your machine. The message channel 2: open failed: connect failed: Connection refused is emitted by the remote SSH server, which accepted your tunnel but then failed to connect to the host and port you asked for, from its side of the network. The tunnel works; the second half of the path is closed, and the remote service or its firewall is what needs looking at, not your SSH configuration.

Who actually sends this message?

An ssh -L tunnel is a path in two halves. The first half runs from your local port to the SSH server: it opens when the command starts, and it is the half everyone looks at. The second half runs from the SSH server to the target you named, and it only opens when something connects: at that moment the server itself attempts the connection, from its own network, with its own view of addresses.

connect failed: Connection refused is the report of that attempt. The word channel gives it away: a channel is opened inside an SSH connection that is already established. If you can read this message, authentication succeeded long ago. This is not a rejected key and not a password problem; looking there is the most expensive wrong turn this failure offers.

Why does the tunnel look open?

Because it is. Here is the failure reproduced end to end, with a tunnel pointing at a port where nothing listens:

ssh -N -L 15433:127.0.0.1:59999 server
nc -z localhost 15433
Connection to localhost port 15433 [tcp/*] succeeded!
channel 2: open failed: connect failed: Connection refused

Both lines tell the truth. nc reached the local port: the first half of the path exists. At the same instant, the server failed to reach the target: the second half does not. A green status light, a local port check, a telnet localhost will all tell you the tunnel works. They only ever test the half that works. The status light of a tunnel manager that merely watches the process tells you even less: it says the process exists, not that either half of the path does.

Your machinelocalhost:15433openSSH serversshdconnect refusedTarget127.0.0.1:59999
The two halves of a tunnel: the message comes from the second one.

The four causes, from most common to most subtle

CauseWhat happenedThe test that confirms it
The service is not runningThe database or app you target is stopped, or movedssh server 'nc -vz 127.0.0.1 5432' fails too
Wrong port or wrong addressA typo in the right-hand side of the -LReread the command: the target is what follows the first colon
The service only listens on localhostYou target a machine's network address while the service is bound to 127.0.0.1ssh server 'ss -tlnp' shows the real listening address
localhost is not the one you thinkIn a -L, the target is resolved by the server, not by your machineReplace the name with an explicit IP address

Kestro makes this distinction for you: it separates "the tunnel is open" from "the target answers", and shows which of the two halves failed. The manual check below remains the right method if you would rather not add a tool, and the guide to tunnels that keep dropping covers the other ways a tunnel can lie to you.

How do you check from the server, not from your desk?

The reflex that settles everything: replay the connection from the place that actually attempts it. One command is enough, and it rides the SSH session you already have:

ssh server 'nc -vz 127.0.0.1 5432'

If this command fails, the problem is entirely on the server side: stopped service, wrong port, local firewall. Your tunnel is innocent, and restarting it will change nothing. If it succeeds while the tunnel still fails, compare what you wrote in the -L with what you just tested: in almost every remaining case, the two do not point at the same thing.

What remains

This message has a near-identical sibling, open failed: administratively prohibited, which does not come from a closed port but from a server configured to forbid tunnels: the answer then lives in sshd_config, not in the target service. If your tunnel only fails after the Mac wakes from sleep, the symptom looks similar but the cause is different: that is the case of the tunnel that dies after sleep. Finally, the reproduction above was done on macOS with OpenSSH; the exact wording can vary between versions, the mechanism does not.