DEV Community

DeployLark
DeployLark

Posted on Originally published at deploylark.com

Docker Port Is Already Allocated: Fix Address Already in Use

You run docker run -p 8080:80 or docker compose up and Docker refuses to start the container. The message is either Bind for 0.0.0.0:8080 failed: port is already allocated or Error starting userland proxy: listen tcp4 0.0.0.0:8080: bind: address already in use. The two look alike, but they point at different owners of the port, and the fix depends on which one you got.

This guide reproduces both errors with nginx:1.30.6-alpine on Docker Engine 26.1.5, then repeats them on Docker Engine 29.9.2 to show the newer wording. Every message below comes from that lab run on November 8, 2026. Demand for this fix is huge. On that day the Stack Overflow question Docker Error bind: address already in use had 1,095,795 views and Bind for 0.0.0.0:4000 failed: port is already allocated had 610,285.

The short version:

  • port is already allocated means another container already publishes that host port. Find it with docker ps --filter publish=8080, then stop it or change your host port.
  • bind: address already in use means something outside Docker's port table holds the port, usually a host service. Find it with sudo ss -ltnp 'sport = :8080' and stop that service.
  • With Compose, the owner is often a project in another directory. Read its labels, then run docker compose -p NAME down.
  • A failed docker run leaves a container in the Created state. Remove it before you retry with the same name.
  • Stopping a container frees its port. Removing it is not required.

Table of contents

Fix port is already allocated

Start with the map. Match the message you see to the cause and the fix:

Table diagram mapping Docker port errors to causes and fixes: port is already allocated, bind address already in use, and the container name conflict after a failed run

Reproduce it with two containers

The first container takes host port 8080. The second asks for the same host port:

docker run -d --name web1 -p 8080:80 nginx:1.30.6-alpine
docker run -d --name web2 -p 8080:80 nginx:1.30.6-alpine
Enter fullscreen mode Exit fullscreen mode

The second command failed with exit code 125:

docker: Error response from daemon: driver failed programming external connectivity on endpoint web2 (494c5c95...): Bind for 0.0.0.0:8080 failed: port is already allocated.
Enter fullscreen mode Exit fullscreen mode

Docker tracks every published host port. When a running container already holds 0.0.0.0:8080, the daemon rejects the new mapping from its own records. The container port (80 in both cases) does not matter. Two containers can both listen on port 80 inside their own network namespaces. Only the host side collides. As the accepted Stack Overflow answer by yamenk puts it: "You need to make sure that the previous container you launched is killed, before launching a new one that uses the same port."

Terminal capture: second nginx container fails with Bind for 0.0.0.0:8080 failed port is already allocated, docker ps filter publish=8080 shows web1, and ss shows docker-proxy listening

Find the container that owns the port

docker ps has a filter for published ports, so you don't have to scan the whole list:

docker ps --filter publish=8080 --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
Enter fullscreen mode Exit fullscreen mode
NAMES     STATUS         PORTS
web1      Up 5 seconds   0.0.0.0:8080->80/tcp, :::8080->80/tcp
Enter fullscreen mode Exit fullscreen mode

On the host, ss showed the listener as docker-proxy, one process for IPv4 and one for IPv6:

LISTEN 0      4096         0.0.0.0:8080      0.0.0.0:*    users:(("docker-proxy",pid=751939,fd=4))
LISTEN 0      4096            [::]:8080         [::]:*    users:(("docker-proxy",pid=751946,fd=4))
Enter fullscreen mode Exit fullscreen mode

If you see docker-proxy there, the owner is a container. Don't kill the proxy process. Stop the container instead.

Free the port or pick another one

You have two clean options. Stop the old container (docker stop web1), or move the new one to a free host port such as -p 8081:80. In the lab, docker stop web1 released 8080 at once. ss showed no listener and a new container took 8080 without errors. You don't need docker rm to free a port.

One trap waits on the retry. The failed run still created web2, and docker ps -a listed it as Created. Running again with the same name, even on a new port, failed:

docker: Error response from daemon: Conflict. The container name "/web2" is already in use by container "dfb7802a...". You have to remove (or rename) that container to be able to reuse that name.
Enter fullscreen mode Exit fullscreen mode

Run docker rm web2 first. After that, docker run -d --name web2 -p 8081:80 nginx:1.30.6-alpine started, and both http://127.0.0.1:8080/ and http://127.0.0.1:8081/ returned 200.

Fix bind: address already in use

When no container owns the port

For this case the lab started a plain host process on port 8082 with python3 -m http.server 8082. Then it asked Docker for the same port:

docker: Error response from daemon: driver failed programming external connectivity on endpoint web3 (3f7ab854...): Error starting userland proxy: listen tcp4 0.0.0.0:8082: bind: address already in use.
Enter fullscreen mode Exit fullscreen mode

docker ps --filter publish=8082 printed nothing. Docker's own table was clean, so the daemon tried to open the socket and the kernel said no. That is the difference between the two messages. "Already allocated" comes from Docker's records. "Address already in use" comes from the operating system.

Terminal capture: Docker fails with listen tcp4 0.0.0.0:8082 bind address already in use, ss shows python3 owns the port, and docker start succeeds after the process stops

Find the process with ss and stop it

Ask the kernel who is listening:

sudo ss -ltnp 'sport = :8082'
Enter fullscreen mode Exit fullscreen mode
LISTEN 0      5            0.0.0.0:8082      0.0.0.0:*    users:(("python3",pid=752469,fd=5))
Enter fullscreen mode Exit fullscreen mode

Run it with sudo. In the lab, plain ss without root listed the docker-proxy socket on 8080 with an empty process column. This tip comes from a highly voted answer by Jamie on the Postgres port question: "If lsof -i :5432 doesn't show you any output, you can use sudo ss -lptn 'sport = :5432' to see what process is bound to the port."

After kill 752469, the listener was gone. The failed container already existed, so docker start web3 was enough, and port 8082 returned 200. On a real server, the owner is usually a packaged service: nginx or apache2 on 80 and 443, postgresql on 5432, mysql on 3306. Stop and disable it with sudo systemctl disable --now nginx, or move your container to another host port. If a database on the host is the reason you can't connect at all, the PostgreSQL Docker auth guide and the MySQL Docker access denied guide cover the login errors that follow.

Fix port conflicts in Docker Compose

Another Compose project holds the port

Compose names projects after their folder. Two folders with the same service and the same ports: line collide:

services:
  web:
    image: nginx:1.30.6-alpine
    restart: unless-stopped
    ports:
      - "8090:80"
Enter fullscreen mode Exit fullscreen mode

docker compose up -d in projA started. The same command in projB failed with Bind for 0.0.0.0:8090 failed: port is already allocated. Running docker compose down in projB would not help, because projB doesn't own the port.

Compose writes the project name and its folder into container labels. Ask for them:

docker ps --filter publish=8090 \
  --format "table {{.Names}}\t{{.Label \"com.docker.compose.project\"}}\t{{.Label \"com.docker.compose.project.working_dir\"}}"
Enter fullscreen mode Exit fullscreen mode

The output named proja and its full path. docker compose ls listed the same project with its compose file. docker compose -p proja down removed it from any directory, and projB then started and served 200 on 8090.

Terminal capture: second Compose project fails with port 8090 already allocated, docker ps labels reveal project proja and its folder, and docker compose -p proja down frees the port

The restart: unless-stopped line matters here. A container with a restart policy comes back with the Docker daemon. In the 29.9.2 lab, a container started with --restart unless-stopped was up again on its port right after dockerd restarted, so an old stack you forgot about can hold a port after every reboot. Take it down with docker compose down, not just docker stop. A UI like Portainer also shows each stack and its published ports in one place.

Scaling a service with a fixed host port

docker compose up -d --scale web=2 on the same file started web-1 and then failed on web-2 with Bind for 0.0.0.0:8090 failed: port is already allocated. Every replica asks for the same host port. Give Compose a range instead:

services:
  web:
    image: nginx:1.30.6-alpine
    ports:
      - "8091-8092:80"
Enter fullscreen mode Exit fullscreen mode

With the range, both replicas started. docker compose ps showed one on 8091 and one on 8092. If you put a reverse proxy in front, you can drop the host port entirely and let the proxy reach the containers over the Compose network. The Traefik labels guide and the Nginx Proxy Manager guide both work that way.

Bind to one IP or let Docker pick a port

Same port on different host IPs

A host port is only taken on the address it is bound to. In the lab, -p 127.0.0.1:8095:80 and -p 127.0.0.2:8095:80 ran side by side, and both addresses returned 200. A third container with plain -p 8095:80 then failed with listen tcp4 0.0.0.0:8095: bind: address already in use. Note that this case produces the kernel message, not the Docker one, even though only containers were involved.

Binding to 127.0.0.1 is a good habit anyway. The Docker port publishing docs warn: "Publishing container ports is insecure by default. Meaning, when you publish a container's ports it becomes available not only to the Docker host, but to the outside world as well."

Let Docker choose a free host port

Publish only the container port and Docker picks a free host port:

docker run -d --name rnd -p 80 nginx:1.30.6-alpine
docker port rnd
Enter fullscreen mode Exit fullscreen mode
80/tcp -> 0.0.0.0:32768
80/tcp -> [::]:32768
Enter fullscreen mode Exit fullscreen mode

The Compose file reference says the same about ports:. You can give both sides "or just the container port. In the latter case, the container runtime automatically allocates any unassigned port of the host" (Compose services reference). This suits test stacks and CI runs where nobody types the URL by hand.

Newer Docker error wording

Docker Engine 29 messages

The same two tests inside docker:29.9.2-dind produced longer messages with a new prefix:

docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint web2 (e1f0829e...): Bind for :::8080 failed: port is already allocated
Enter fullscreen mode Exit fullscreen mode
docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint web3 (d9beba20...): failed to bind host port 0.0.0.0:8082/tcp: address already in use
Enter fullscreen mode Exit fullscreen mode

Search for the tail of the line, not the prefix. Bind for :::8080 is the IPv6 side of the same conflict, and failed to bind host port ... address already in use replaces the older Error starting userland proxy text. The causes and fixes are the same as above. docker ps --filter publish=8080 worked unchanged on 29.9.2, and netstat -ltnp inside the dind host still showed docker-proxy as the listener.

Terminal capture on Docker Engine 29.9.2: failed to set up container networking with Bind for :::8080 failed port is already allocated, and failed to bind host port 0.0.0.0:8082/tcp address already in use

If you hit permission errors before you even get to the port problem, fix access to the daemon first with the docker.sock permission guide. The Uptime Kuma guide shows this same port error for a second copy of an app on 3001.

FAQ

What does "port is already allocated" mean in Docker?

Another container already publishes that host port. Docker checks its own records and refuses the mapping. Run docker ps --filter publish=PORT to see which one, as in SO 46176584.

How do I find which process is using a port on Linux?

Run sudo ss -ltnp 'sport = :PORT'. The users: column shows the process name and PID. If it says docker-proxy, a container owns the port. See SO 38249434.

Why does docker ps show nothing but the port is still in use?

A process outside Docker holds the port, such as a host nginx, apache2 or postgresql service, or another container bound to a specific host IP. In the lab, docker ps --filter publish=8082 was empty while ss showed python3. Threads like SO 37971961 end with stopping the host service.

Can two Docker containers use the same port?

Yes on the container side, and on the host side if they use different host IPs. Both test containers listened on 80 inside. On the host, 127.0.0.1:8095 and 127.0.0.2:8095 worked together, but a third on 0.0.0.0:8095 failed.

Does stopping a container free its port?

Yes. After docker stop web1, ss showed nothing on 8080 and a new container took it. A restart policy can bring the old one back with the daemon, so use docker compose down or docker rm for stacks you no longer want.

How do I let Docker pick a free port automatically?

Publish only the container port, for example -p 80 or ports: ["80"], then read the result with docker port NAME. The lab got 32768. The Compose ports reference documents the same behavior.

Top comments (0)