Resolving Port Conflicts (Address Already In Use) on Linux
How to diagnose and fix 'Address already in use' errors on Linux, including finding processes using ports, SO_REUSEADDR, and proper shutdown procedures.
Resolving Port Conflicts (Address Already In Use) on Linux
The "Address already in use" error is one of the most common networking issues on Linux servers. During development of a WebSocket service in Lisbon, I hit this error constantly after force-killing processes. This guide covers systematic diagnosis and multiple solutions.
Environment
- OS: Ubuntu 22.04 LTS
- Application: Node.js WebSocket server on port 8080
- Error:
EADDRINUSEafter process termination
$ node --version
v18.17.0
$ cat /etc/os-release | head -3
PRETTY_NAME="Ubuntu 22.04.3 LTS"The Problem
$ node server.js
Error: listen EADDRINUSE: address already in use :::8080
at Server.setupListenContext [as _listen2] (net.js:1334:16)
at doListen (net.js:1467:7)Even after killing the previous process, the port remains bound:
$ kill -9 $(pgrep -f "node server.js")
$ node server.js
Error: listen EADDRINUSE: address already in use :::8080Analysis
Understanding TIME_WAIT State
When a TCP connection closes, it enters a TIME_WAIT state for up to 60 seconds (default). During this period, the port cannot be rebound:
$ ss -tlnp | grep :8080
LISTEN 0 128 :::8080 :::* users:(("node",pid=12345,fd=6))
$ ss -tanp | grep :8080
TIME-WAIT 0 0 :::8080 :::* users:(("node",pid=12345,fd=6))Step 1: Find What Is Using the Port
# Using lsof
$ sudo lsof -i :8080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 12345 joel 6u IPv6 45678 0t0 TCP *:8080 (LISTEN)
# Using ss
$ sudo ss -tlnp | grep :8080
LISTEN 0 128 *:8080 *:* users:(("node",pid=12345,fd=6))
# Using fuser
$ sudo fuser 8080/tcp
8080/tcp: 12345Step 2: Check Socket States
$ ss -tan | grep :8080
LISTEN 0 128 *:8080 *:* users:(("node",pid=12345,fd=6))
TIME-WAIT 0 0 127.0.0.1:8080 127.0.0.1:43210
ESTABLISHED 0 0 127.0.0.1:8080 127.0.0.1:43210The TIME-WAIT connections are the problem.
Step 3: Check Kernel Parameters
# Check current TIME_WAIT duration
$ cat /proc/sys/net/ipv4/tcp_fin_timeout
60
# Check if port reuse is allowed
$ cat /proc/sys/net/ipv4/tcp_tw_reuse
0Solution
Fix 1: Kill All Processes on the Port
# Using fuser (most reliable)
$ sudo fuser -k 8080/tcp
# Verify port is free
$ sudo lsof -i :8080
# No output means port is free
# Now start the server
$ node server.js
Server listening on port 8080Fix 2: Enable SO_REUSEADDR in Application
// Node.js - Enable address reuse
const net = require('net');
const server = net.createServer();
server.on('error', (e) => {
if (e.code === 'EADDRINUSE') {
console.log('Port in use, retrying...');
setTimeout(() => {
server.close();
server.listen({ port: 8080, reuseAddress: true });
}, 1000);
}
});
server.listen({ port: 8080, reuseAddress: true });# Python - Enable address reuse
import socket
import socketserver
class ReusableServer(socketserver.TCPServer):
allow_reuse_address = True
allow_reuse_port = True
server = ReusableServer(('0.0.0.0', 8080), MyHandler)
server.serve_forever()Fix 3: Reduce TIME_WAIT Duration
# Reduce FIN timeout (default 60, set to 30)
$ sudo sysctl -w net.ipv4.tcp_fin_timeout=30
# Enable TIME_WAIT socket reuse
$ sudo sysctl -w net.ipv4.tcp_tw_reuse=1
# Make persistent
$ echo "net.ipv4.tcp_fin_timeout = 30" | sudo tee -a /etc/sysctl.conf
$ echo "net.ipv4.tcp_tw_reuse = 1" | sudo tee -a /etc/sysctl.conf
$ sudo sysctl -pFix 4: Use SO_REUSEPORT (Linux 3.9+)
// C - Enable port reuse at socket level
#include
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
int optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); # Python - SO_REUSEPORT
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
sock.bind(('0.0.0.0', 8080))
sock.listen(5)Fix 5: Use systemd for Clean Shutdown
Configure proper shutdown to avoid orphaned sockets:
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/node /opt/app/server.js
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=30
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target# Clean restart
$ sudo systemctl stop myapp
$ sleep 5 # Wait for TIME_WAIT to clear
$ sudo systemctl start myappQuick Reference
# Find what uses a port
$ lsof -i :PORT
$ ss -tlnp | grep :PORT
$ fuser PORT/tcp
# Kill process on a port
$ fuser -k PORT/tcp
# Check socket states
$ ss -tan | grep :PORT
# Set reuse options
$ sysctl -w net.ipv4.tcp_tw_reuse=1
$ sysctl -w net.ipv4.tcp_fin_timeout=30Lessons Learned
- Never use
kill -9for application shutdowns - use SIGTERM first to allow graceful cleanup. - Always implement SO_REUSEADDR in server applications during development.
- Check TIME_WAIT before assuming a process is still running.
- Use systemd's
KillMode=mixedfor proper service shutdown with child process cleanup. - Monitor port usage with a simple script to catch orphaned sockets early.
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.