Skip to main content
DevOps Insightsguides & answers

Linux and macOS · troubleshooting

bind: Address already in use (EADDRINUSE)

Your program asked the operating system for a network port that something else is already listening on, so it could not start listening there. Usually an earlier copy of the same program still running, another service on that port, or a restart that came too soon.

Reproduced on Node.js 25.9.0, . Where the text says “reproduced”, the behaviour was run on that version, not taken from documentation.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 9 sections

Before you start

  • The port number from the message, and a terminal on the machine where the program runs.

Run this first

step 1 of 2
lsof -nP -iTCP:PORT -sTCP:LISTEN

Look for The command and PID; nothing at all points at TIME_WAIT or a container

Names the process listening on the port, on macOS and Linux.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

What does lsof -nP -iTCP:PORT -sTCP:LISTEN (or sudo ss -ltnp) show?

Cause space

5 of 5 still possible

  • An earlier copy of the same program is still runningCommon
  • A different service uses that portCommon
  • Listening on 0.0.0.0 while something holds the port on one addressOccasional
  • A quick restart while old connections are in TIME_WAITOccasional
  • A container publishes the portOccasional

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    lsof -nP -iTCP:PORT -sTCP:LISTEN

    Names the process listening on the port, on macOS and Linux.

    Look for The command and PID; nothing at all points at TIME_WAIT or a container

  2. Step 2

    sudo ss -ltnp 'sport = :PORT'

    The Linux equivalent, with the address each listener uses.

    Look for Whether the holder is on 0.0.0.0, 127.0.0.1 or another address

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

An earlier copy of the same program is still running

Common

A dev server left running in another terminal, a process that did not exit when its terminal closed, or a service manager that already started it.

Confirm

lsof -nP -iTCP:PORT -sTCP:LISTEN

The program and process ID holding the port (on Linux, sudo ss -ltnp 'sport = :PORT' shows the same)

Fix

  • Stop the old copy the way it was started: Ctrl+C in its terminal, or systemctl stop for a service.
  • If it is truly stray, end it by process ID with kill PID, and only use kill -9 if it does not exit.

A different service uses that port

Common

Ports such as 80, 3000, 5000, 5432 and 8080 are popular defaults: a system web server, a database or another project may already use it.

Confirm

sudo ss -ltnp 'sport = :PORT'

A program you did not expect on the port

Fix

  • Run your program on another port, usually through its configuration or a PORT environment variable.
  • Or stop or reconfigure the other service if you no longer need it on that port.

Listening on 0.0.0.0 while something holds the port on one address

Occasional

0.0.0.0 covers every address on the machine, so it conflicts with a program on 127.0.0.1 or a specific address with the same port.

Confirm

sudo ss -ltnp 'sport = :PORT'

A listener on 127.0.0.1:PORT or another single address

Fix

  • Pick a different port, or bind your program to a specific address that is free, for example 127.0.0.1 if only local clients need it.

A quick restart while old connections are in TIME_WAIT

Occasional

The program itself exited, but its recent connections linger briefly. A server that does not set SO_REUSEADDR cannot listen again until they expire.

Confirm

ss -tan state time-wait 'sport = :PORT'

Connections in TIME_WAIT on the port, and no process listening on it

Fix

  • Set SO_REUSEADDR on the listening socket before bind, in your own socket code. Most server frameworks already do.
  • Otherwise wait a short while and start it again.

A container publishes the port

Occasional

A running container with that port published holds it on the host, even if you forgot it was there.

Confirm

docker ps --format '{{.Names}} {{.Ports}}'

A container whose ports include the host port, such as 127.0.0.1:3029->3000/tcp; ss names the holder as docker-proxy

Fix

  • Stop that container, or publish a different host port. The Docker side of this error has its own page.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

Only one program at a time can listen on a given port and address. When a second one asks for it, the operating system refuses, and the program reports Address already in use. The fix is to find what holds the port and decide which of the two should have it.

Words used on this page

Listening
Waiting for incoming connections on a port. Two programs cannot listen on the same port and address at once.
0.0.0.0
All of the machine's IPv4 addresses. Listening there conflicts with any program on the same port at a specific address, such as 127.0.0.1.
TIME_WAIT
A short state a closed TCP connection stays in, so late packets are not mistaken for a new connection.
SO_REUSEADDR
A socket option that lets a server listen on a port again while old connections on it are still in TIME_WAIT.
What is actually happening

Reproduced on 22 October 2026 by starting a listener and then a second program on the same port. Python printed OSError: [Errno 48] Address already in use on macOS and OSError: [Errno 98] Address already in use on Linux: the same error under each system's own number. Node.js 25.9.0 on macOS and Node.js 18.19.1 on Linux both printed Error: listen EADDRINUSE: address already in use 127.0.0.1:PORT. Go servers word it as listen tcp :PORT: bind: address already in use; that wording was not reproduced here.

On Linux, listening on 0.0.0.0 failed while another program listened on 127.0.0.1 with the same port, because 0.0.0.0 includes 127.0.0.1.

A server restarted straight after it closed connections can also hit this, because those connections linger in TIME_WAIT for a short while. On Linux the new socket could take the port during TIME_WAIT only when both the old and the new socket set SO_REUSEADDR. Node.js's own HTTP server restarted at once with a TIME_WAIT connection on its port, so it sets the option itself; a server you write with raw sockets has to set it.

How to tell this is your problem
WhereWhat you see
Node.jsError: listen EADDRINUSE: address already in use 127.0.0.1:3000
PythonOSError: [Errno 98] Address already in use (Linux), [Errno 48] on macOS

How to know it is actually fixed

  • lsof or ss shows only your program listening on the port, and clients can connect.

Stopping it happening again

  • Make the port configurable (a PORT environment variable) so two services never have to fight over a default.
  • Run long-lived services under a service manager, so there is one copy and a clean way to stop it.

Security considerations

  • Before killing the process that holds the port, check what it is. Stopping the wrong service, or a database, can cause an outage of its own.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it