Skip to content
DevOps2026-09-083 min read

Docker port is already allocated: Finding and Freeing the Taken Port

Symptom: the container won't start — a port couldn't be handed out

# During docker run
docker: Error response from daemon: driver failed programming external
connectivity on endpoint ...: Bind for 0.0.0.0:8080 failed: port is already allocated.

# Or the lower-level form
Error starting userland proxy: listen tcp4 0.0.0.0:80: bind: address already in use

One-line diagnosis: the host port you're mapping to is already taken. Mind the subject — not the container-internal port (that side is NAT, repeats are fine), but the host port on the left side of -p.

Step one: is the squatter a container or a host process?

# Suspect 1: another container mapped the same port
docker ps --filter "publish=8080"

# Suspect 2: a regular process on the host (nginx, a local dev server...)
sudo ss -tlnp | grep :8080

Run both; whoever is listening becomes obvious. The remedies differ completely:

A container holds it:

docker ps -a --filter "publish=8080"    # include stopped ones
docker rm -f <container-name-or-id>    # remove the old container, port freed
docker stop <container-name>           # or just stop it — that frees the port too

A host process holds it: either stop it (systemctl stop nginx) or rerun your container on a different port.

Frequent scenario 1: the compose config changed, the old container stayed

Compose manages containers by project name (default = directory name). Two common collisions:

  1. You edited docker-compose.yml ports to "start another copy", but the containers from the previous docker compose up are still there — run docker compose down first;
  2. Two different directories share a name (say both app/): identical compose project names fight over containers and ports. Isolate with an explicit project name:
docker compose -p projectA up -d

Frequent scenario 2: container removed, port still held (stale docker-proxy)

Rarely, docker ps shows no occupant while ss shows a docker-proxy process listening — restarting the Docker service clears the leftover:

sudo systemctl restart docker

That's the last resort: all containers restart with it, so assess the impact first on production.

A counterintuitive detail: different bind addresses can coexist

docker run -p 127.0.0.1:8080:80 --name a ...   # loopback only
docker run -p 192.168.1.5:8080:80 --name b ... # a specific NIC

The conflict check is on the "address + port" combination, not the port alone. 127.0.0.1:8080 conflicts with 0.0.0.0:8080 (the latter includes the former), but 127.0.0.1:8080 and 192.168.1.5:8080 can coexist. This detail saves you one round of "nobody is using it, why the conflict" — the invisible binding on the other side is usually a 0.0.0.0.

Relation to host-side EADDRINUSE

The same event from two viewpoints: your application process fails to listen on a taken port with EADDRINUSE; your container fails to map one with port is already allocated. The diagnostic flow is shared — see Port already in use: EADDRINUSE troubleshooting. The opposite direction, "can't connect to a port" (ECONNREFUSED), is a different problem entirely: ECONNREFUSED troubleshooting.

Checklist

  1. docker ps --filter "publish=<port>" — does a container hold it?
  2. ss -tlnp | grep :<port> — does a host process hold it? (run both checks)
  3. Old containers: docker rm -f; compose scenarios: docker compose down first
  4. Nobody visible but still failing? systemctl restart docker clears stale docker-proxy
  5. Port reuse: 127.0.0.1 conflicts with 0.0.0.0, but not with a specific NIC IP

Provided by ToolVault. Related tools: Dockerfile Generator, CIDR Calculator, HTTP Status Codes. Related reading: Port already in use (EADDRINUSE), ECONNREFUSED troubleshooting. See the homepage for more developer tools.


Advertisement