How to fix channel_setup_fwd_listener: cannot listen to port: port in SSH
SSH port forwarding fails because the client or server cannot bind a listening socket on the requested port — usually because the port is already in use, is privileged, or a stale listener still holds it.
Quick fix
Fixes channel_setup_fwd_listener: cannot listen to port: port
# Linux: show the listening socket and the owning PID/program
ss -ltnp 'sport = :8080'
# macOS / portable
lsof -nP -iTCP:8080 -sTCP:LISTEN- Identify which process already owns the port
- Stop the specific stale listener (target the PID, never blanket-kill SSH)
- Avoid privileged ports instead of escalating privileges
- Remove duplicate forwarding directives from your SSH config
# Linux: show the listening socket and the owning PID/programss -ltnp 'sport = :8080'# macOS / portablelsof -nP -iTCP:8080 -sTCP:LISTENchannel_setup_fwd_listener: cannot listen to port: port
What this error means
When you run SSH with `-L` (local forwarding) or `-R` (remote forwarding), SSH must open a listening socket on the forwarding port. `channel_setup_fwd_listener: cannot listen to port: <port>` means the `bind()`/`listen()` call for that socket was refused. For `-L`, the listener is created by your local SSH client; for `-R`, it is created by the remote `sshd`. SSH then emits a follow-up message such as `Could not request local forwarding` or `Warning: remote port forwarding failed`. This is a local/remote socket-binding problem, not a network connectivity or authentication problem — the SSH session itself usually connects fine. The kernel refuses the bind for one of a small set of reasons: another process already holds the address/port, the port is privileged and you are unprivileged, or a previous forwarder is still alive and holding the socket. Identifying which process owns the port is almost always the fastest path to a fix.
Typical symptoms
- The SSH login succeeds, but you immediately see `channel_setup_fwd_listener: cannot listen to port: <port>`.
- A follow-up message appears: `Could not request local forwarding` (for `-L`) or `Warning: remote port forwarding failed for listen port <port>` (for `-R`).
- The forwarded port does not accept connections; clients pointed at it get connection-refused.
- Forwarding worked in a previous session and fails when you reconnect, suggesting the old listener is still around.
- The failure is reproducible only for one specific port number; other ports forward fine.
Common causes
- Another process is already listening on the requested port — most commonly a leftover SSH forwarder from a previous session that did not exit, or the local application you are trying to forward to.
- A previous SSH connection (for example a backgrounded `-f`/`-N` tunnel or one held open by `ControlMaster`/`ControlPersist`) is still alive and still holding the listening socket.
- You are trying to bind a privileged port below 1024 as a non-root user, which the kernel refuses.
- For remote (`-R`) forwarding, `sshd` is binding only to loopback (default) or `GatewayPorts` / the requested bind address is misconfigured, so the listen on the remote side fails or is restricted.
- Your `~/.ssh/config` (or a `Match`/`Host` block) defines a duplicate `LocalForward`/`RemoteForward` for the same port, so SSH tries to open the same listener twice.
- An IPv4/IPv6 dual-stack mismatch: the port is free on one family but already bound on the other, so the bind fails.
How to fix "channel_setup_fwd_listener: cannot listen to port: port"
Find out exactly what is holding the forwarding port before changing anything. Replace 8080 with your actual port:
# Linux: show the listening socket and the owning PID/program
ss -ltnp 'sport = :8080'
# macOS / portable
lsof -nP -iTCP:8080 -sTCP:LISTENFor a remote (-R) tunnel, run the same command on the SSH server, since sshd creates that listener there.
If nothing is listed, the port is actually free and the cause is privilege or configuration (see the steps below). If a process is listed, note its PID and command — the next step decides what to do with it.
If the listener is a leftover SSH forwarder you no longer need, terminate only that process using the PID you found in step 1. Send a graceful SIGTERM first:
# Replace 12345 with the exact PID from `ss`/`lsof`
kill 12345
# Confirm it is gone; only then escalate if it is truly stuck
ss -ltnp 'sport = :8080'
kill -9 12345 # last resort, only for that one PIDDo not run pkill ssh or pkill -9 ssh: that kills every SSH process you own, tearing down unrelated live sessions and tunnels. If the listener belongs to a real application (not SSH), do not kill it — forward to a different local port instead (step 5).
If the tunnel was started with SSH connection multiplexing, close it cleanly instead of killing it:
ssh -O exit -S <control-socket-path> user@remote # or check: ssh -O check user@remotePorts below 1024 require elevated privileges to bind. The safe fix is to not bind a privileged port: pick a high local port (for example 8080 instead of 80) and have your local client connect to that high port.
# Avoid: requesting a privileged local listen port as a normal user
# ssh -L 80:localhost:80 user@remote.com # bind on :80 will be refused
# Prefer: listen on a high local port, forward to the privileged remote port
ssh -L 8080:localhost:80 user@remote.com
# then point your local client at http://localhost:8080Do not run the whole SSH client under sudo just to open a privileged listener — that runs your entire SSH session, agent access, and key handling as root, which is unnecessary and risky. If a privileged local port is genuinely required (for example software that hard-codes port 443), grant that capability narrowly rather than running SSH as root — e.g. start SSH via authbind --deep ssh ..., or use a local firewall/pf/iptables redirect from the privileged port to a high port. Reserve these for cases where a high port truly cannot be used.
A repeated LocalForward/RemoteForward for the same port makes SSH try to open the listener twice. Inspect the effective configuration for your host:
ssh -G user@remote.com | grep -i forwardThis expands all matching Host/Match blocks and shows every forward that will be applied. If you see the same listen port more than once, edit ~/.ssh/config and remove the duplicate:
Host myhost
HostName remote.com
User user
LocalForward 8080 localhost:80
# delete any second line that re-declares LocalForward 8080 ...Also remember that command-line -L/-R flags add to (do not replace) config-file forwards, so a port declared in both places will collide.
If the chosen port is owned by an application you must not disturb, simply pick an unused high port. Anything in the ephemeral range is fine, but verify it is free first:
ss -ltn 'sport = :54321' # should print no listening socket
ssh -L 54321:destination.internal:8080 user@remote.comThen connect your local client to localhost:54321. This sidesteps the conflict without killing other processes and is a good, non-destructive workaround while you investigate the root cause.
With -R, the listener lives on the SSH server. By default sshd binds remote forwards to loopback (127.0.0.1) only. If you request a public bind address without permission, the listen fails.
To expose a remote-forwarded port beyond loopback, set GatewayPorts appropriately in the server's /etc/ssh/sshd_config:
# Lets the client choose the bind address (e.g. ssh -R '0.0.0.0:8080:...')
GatewayPorts clientspecifiedThen reload sshd:
sudo systemctl reload ssh # or: sudo systemctl reload sshdPrefer clientspecified over a blanket yes so each tunnel explicitly opts into a public bind address. Confirm the remote port is actually free on the server with ss -ltnp there.
If ss/lsof shows the port free but the bind still fails, a different address family may already hold it, or a policy may block it. Force a single family to isolate the problem:
ssh -4 -L 8080:localhost:80 user@remote.com # force IPv4
ssh -6 -L 8080:localhost:80 user@remote.com # force IPv6On SELinux systems, a non-standard listen port may need a label; check before changing anything:
sudo semanage port -l | grep -w 8080For host firewalls, confirm the port is permitted (review rules; do not blanket-disable the firewall):
sudo iptables -S | grep 8080
sudo firewall-cmd --list-ports # firewalld-based systemsNote that for a purely local -L listener bound to 127.0.0.1, host firewalls usually are not involved; this step matters mainly for remote (-R) listeners or forwards bound to a public address.
Advanced notes
SSH opens local-forward listeners with SO_REUSEADDR, so a clean TIME_WAIT state from a previous connection on the *connect* side does not normally block a new listener — if a bind is being refused, an actual live listener is almost always still holding the port. Tunables like net.ipv4.tcp_tw_reuse apply to the connecting side and are not a fix for a failed listen(); avoid changing them for this error.
For background tunnels (ssh -f -N -L ...) and multiplexed connections (ControlMaster/ControlPersist), the listener can outlive your interactive shell. Use ssh -O check/ssh -O exit against the control socket to manage them cleanly instead of killing processes.
For -R forwards, you can let sshd pick a free port by requesting port 0 (ssh -R 0:localhost:80 ...); recent OpenSSH prints the allocated port. The remote listener still binds to loopback unless GatewayPorts permits otherwise. If diagnostics are unclear, add -v to the SSH command — the verbose log shows the exact forward request and which side rejected the bind.
Frequently asked questions
- What does "channel_setup_fwd_listener: cannot listen to port: port" mean?
- When you run SSH with -L (local forwarding) or -R (remote forwarding), SSH must open a listening socket on the forwarding port. channel_setup_fwd_listener: cannot listen to port: <port> means the bind()/listen() call for that socket was refused. For -L, the listener is created by your local SSH client; for -R, it is created by the remote sshd.
- How do I fix "channel_setup_fwd_listener: cannot listen to port: port"?
- SSH port forwarding fails because the client or server cannot bind a listening socket on the requested port — usually because the port is already in use, is privileged, or a stale listener still holds it.
- What causes "channel_setup_fwd_listener: cannot listen to port: port"?
- Another process is already listening on the requested port — most commonly a leftover SSH forwarder from a previous session that did not exit, or the local application you are trying to forward to. A previous SSH connection (for example a backgrounded -f/-N tunnel or one held open by ControlMaster/ControlPersist) is still alive and still holding the listening socket. You are trying to bind a privileged port below 1024 as a non-root user, which the kernel refuses.
- Is the "channel_setup_fwd_listener: cannot listen to port: port" error serious?
- It is a low-severity error — more of a blocker than a risk. The steps above resolve it.