SSH local port forwarding fails when the specified local port is already in use by another process. This occurs when establishing tunnels with the -L flag and attempting to bind to a port that another service occupies.
When you use SSH local port forwarding with the -L flag (e.g., ssh -L 8080:remote.host:80), the SSH client attempts to bind a listening socket to your local machine on the specified port. If that port is already occupied by another process, the bind operation fails and SSH cannot establish the forwarding tunnel. This error typically manifests as 'bind: Address already in use' or 'Could not request local forwarding' in the SSH output.
Before changing anything, identify what's occupying your desired port.
On Linux/macOS:
lsof -i :8080
ss -tulpn | grep 8080On Windows:
netstat -ano | findstr :8080This shows the process ID (PID) and process name using the port.
You have two options:
Option A: Terminate the blocking process (if safe)
kill -9 <PID> # Replace <PID> with the process ID from step 1Option B: Use a different local port (recommended)
ssh -L 8081:remote.host:80 [email protected]Choose a port number above 1024 (if not using sudo) and above 49151 if possible.
If the error mentions both IPv4 and IPv6 binding attempts, force SSH to use IPv4:
ssh -4 -L 8080:127.0.0.1:80 [email protected]The -4 flag tells SSH to use only IPv4 addresses, avoiding dual-stack binding issues.
Confirm the SSH server allows TCP forwarding. Connect to the server and check:
grep -i AllowTcpForwarding /etc/ssh/sshd_configIf it shows AllowTcpForwarding no, the server admin needs to change it to yes and restart sshd:
sudo sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/' /etc/ssh/sshd_config
sudo systemctl restart sshdAfter resolving the port conflict, retry with verbose mode to confirm success:
ssh -v -L 8080:remote.host:80 [email protected]Look for output like:
Local forwarding listening on 127.0.0.1 port 8080.
Forwarding to remote.host port 80.This confirms the tunnel is now established.
Connection Multiplexing Issues: If you use ControlMaster for connection sharing, a stale control socket can cause forwarding requests on subsequent connections to fail. Check ~/.ssh/controlmasters/ for old sockets and remove them: rm ~/.ssh/controlmasters/*.
Privileged Ports: Ports below 1024 (e.g., 80, 443) are reserved and require root/sudo to bind. If your local user isn't root, use a port above 1024 and optionally set up a local firewall rule to redirect traffic: sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080.
TIME_WAIT State: Even after killing a process, the port may remain in TIME_WAIT state for 30-120 seconds. Either wait or use ssh -L 127.0.0.1:8080:... instead of 0.0.0.0:8080 to bind only to localhost.
Remote Service Verification: Ensure the remote service you're forwarding to is actually running and listening. On the remote server: ss -tulpn | grep :80 (replace 80 with your target port).
Load key "/home/user/.ssh/id_rsa": invalid format
How to fix 'Load key invalid format' in SSH
Bad owner or permissions on /home/user/.ssh/config
How to fix "Bad owner or permissions on .ssh/config" in SSH
Error connecting to agent: Connection refused
How to fix "Error connecting to agent: Connection refused" in SSH
Connection closed by UNKNOWN port 65535
How to fix 'Connection closed by UNKNOWN port 65535' in SSH
Offending ECDSA key in /home/user/.ssh/known_hosts:line
How to fix "Offending ECDSA key in known_hosts" in SSH