troubleshooting2025-07-03·7·11/348

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: EADDRINUSE after 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 :::8080

Analysis

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:            12345

Step 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:43210

The 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
0

Solution

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 8080

Fix 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 -p

Fix 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 myapp

Quick 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=30

Lessons Learned

  1. Never use kill -9 for application shutdowns - use SIGTERM first to allow graceful cleanup.
  2. Always implement SO_REUSEADDR in server applications during development.
  3. Check TIME_WAIT before assuming a process is still running.
  4. Use systemd's KillMode=mixed for proper service shutdown with child process cleanup.
  5. 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.