TL;DR
Something else is already listening on the port your app wants to use. Find it with ss -tlnp | grep : or lsof -i :, then kill it or change your app's port.
# Find what's using port 8080
ss -tlnp | grep :8080
# Kill it (replace PID with the actual number)
kill -9
# Then restart your service
systemctl restart your-service
What's Actually Happening
Every network service claims a port by calling bind() on a socket. The error bind: Address already in use means the OS refused that claim because another process already owns that port โ or a recently-stopped process left the socket in a TIME_WAIT state and the OS hasn't released it yet.
The two most common situations:
- You restarted your app quickly and the old process is still cleaning up (
TIME_WAIT) - A completely different process grabbed the port โ another instance of your app, a conflicting service, or a zombie from a previous crash
Step 1: Identify the Process Holding the Port
Replace 8080 with whatever port you're trying to use.
Using ss (preferred on modern Linux)
ss -tlnp | grep :8080
Sample output:
LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("node",pid=12345,fd=18))
The PID is right there โ 12345 in this example, running a Node.js process.
Using lsof
lsof -i :8080
Sample output:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 12345 ubuntu 18u IPv4 98765 0t0 TCP *:8080 (LISTEN)
Using fuser
fuser 8080/tcp
This prints just the PID โ useful for scripting.
Step 2: Decide What to Do With It
Option A โ Kill the old process
If it's a stale instance of your own app:
# Graceful kill first
kill 12345
# If it doesn't die in a few seconds, force it
kill -9 12345
Then restart your service normally.
Option B โ Stop a system service that's using the port
If you see something like nginx, apache2, or postgres occupying your port:
# Check what service it belongs to
systemctl status nginx
# Stop it
systemctl stop nginx
Option C โ Kill everything on the port in one shot
fuser -k 8080/tcp
This kills all processes bound to that port. Use with care if you're on a shared server.
Option D โ Change your application's port
Sometimes the port is legitimately in use by something you shouldn't touch. In that case, configure your app to listen on a different port instead. For example, in a Node.js app:
// Change this
const PORT = process.env.PORT || 3001;
app.listen(PORT);
Or set it via environment variable when starting:
PORT=3001 node server.js
Step 3: Handle TIME_WAIT (Quick Restart Scenario)
If you stopped your service and immediately restarted it, you might still see the error even though your own process is gone. The kernel keeps the socket in TIME_WAIT for a short period (usually 60 seconds) to ensure any delayed packets are handled cleanly.
The cleanest fix for services you control is to set SO_REUSEADDR in your application code. Most frameworks and servers do this automatically, but if you're writing raw socket code:
// In C
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
For system services, a quick workaround is to just wait 30โ60 seconds and retry. Or use ss -s to watch the TIME_WAIT count drop:
watch -n1 'ss -s'
Step 4: Verify the Fix
After you've freed the port (or changed your config), confirm the port is clear before starting your service:
# Should return nothing if port is free
ss -tlnp | grep :8080
Then start your service and check it's actually listening:
systemctl start your-service
# Confirm it's up
ss -tlnp | grep :8080
# Test with curl
curl -v http://localhost:8080/health
Bonus: Find Conflicting Ports Before Starting
Before deploying a new service, it's worth checking which ports are already occupied on your server:
# List all listening ports
ss -tlnp
# Or with netstat if ss isn't available
netstat -tlnp
If you're working with containers or complex network setups and need to figure out CIDR ranges or subnet assignments alongside your port planning, the IP Subnet Calculator on ToolCraft is handy for doing network math quickly in the browser โ no data uploaded, fully private.
Preventing This in the Future
- Use
SO_REUSEADDRin your socket code โ eliminates TIME_WAIT restarts - Document your service's ports โ keep a simple list of which port each service uses to avoid accidental conflicts when adding new services
- Use a process manager โ tools like
systemd,pm2, orsupervisorhandle clean shutdown before restart, reducing port conflicts from stale processes - Set
Restart=alwayswithRestartSec=2in systemd units โ gives the kernel time to release sockets between restarts

