Tech Digest

Guide

Why does Docker say port is already allocated?

Docker prints port is already allocated only when another running container has already published the same host address, port and protocol. A host process, or an overlapping address such as 0.0.0.0 against 127.0.0.1, produces a different error, and a stopped container produces neither.

Last reviewed

Why does Docker say port is already allocated?

Because another running container has already published the same host IP, port and protocol, and Docker's own port allocator refuses the second request before it ever asks the kernel. Stopped and created containers do not hold ports. Find the holder with docker ps --filter publish=<port>, which matches the host port. If the error says address already in use instead, the holder is a host process or a container published on an overlapping address, and sudo ss -ltnp 'sport = :<port>' names it.

Because another running container has already published the same host address, port and protocol. The message is Docker's own: its port allocator keeps a table of what each container has published, and refuses a second request for an identical entry before the kernel is ever asked. That narrows the search a lot. A service installed directly on the host, such as nginx or Pi-hole from a package, cannot cause this exact message, and neither can a stopped container. Run docker ps --filter publish=8080, with your port, and the container it returns is the holder.

The first answer, repeated on most forum threads, is that a stopped container still holds its port, so you should run docker ps -a and remove everything that has exited. It is wrong. Stopping a container releases its ports immediately, and we could not make an exited or created container block anything. The advice survives because the commands that go with it, docker compose down or a broad docker rm -f, often also remove the running container that really held the port.

The second answer is "something else on the host is listening, check ss or netstat". That is the right diagnosis for a different error. When a host process has the port, Docker does not say "allocated", it says address already in use. Telling the two messages apart is the fastest diagnosis you have.

What blocked what, measured#

We ran each case on Docker Engine Engine 28.1.1 with Compose 2.35.1 on Linux kernel 5.4, using alpine:3.22 containers running sleep, published on loopback addresses so nothing was reachable from outside.

Already holding the portThen requestedResult
Running container, 127.0.0.1:18701127.0.0.1:18701Bind for 127.0.0.1:18701 failed: port is already allocated
Same container, stopped127.0.0.1:18701Starts
Container only created, never startedSame addressStarts
Host process bound to 127.0.0.1:18702127.0.0.1:18702failed to bind host port for 127.0.0.1:18702:...: address already in use
Same host process18702:80, meaning 0.0.0.0address already in use
Same host process127.0.0.2:18702Starts
Running container, 127.0.0.1:18703127.0.0.2:18703Starts
Running container, 127.0.0.1:187030.0.0.0:18703address already in use
Running container, 0.0.0.0:18704127.0.0.1:18704address already in use
Running container, TCP 127.0.0.1:18707UDP, same address and portStarts

Rows eight and nine are the surprise. Two containers can collide and still get address already in use, not "allocated", because the allocator in Moby's portallocator.go keeps a separate table for each address string. 0.0.0.0 and 127.0.0.1 are different keys to it, so it approves the request, and the kernel then refuses the bind, since 0.0.0.0 already covers every address. So the "allocated" message always means another container, while address already in use can mean a host process or a container on an overlapping address.

A failed docker run is not clean either. Every refusal above left the new container behind in Created state, holding its name, so the retry fails with a name conflict until you docker rm it.

Three messages turn up around this problem, and each points somewhere different:

MessageWhat holds the portWhere to look
Bind for 127.0.0.1:8080 failed: port is already allocatedA running container on that exact address and protocoldocker ps --filter publish=8080
failed to bind host port for ...: address already in useA host process, or a container on an overlapping addresssudo ss -ltnp 'sport = :8080'
Conflict. The container name "/app" is already in useNothing; your previous failed attempt left a container behinddocker ps -a, then docker start or docker rm it

Because the allocator only matches identical entries, the address in the first message is also the holder's address. The third message is the one that makes people think a stopped container is blocking the port: the port is free, but the name is not, and docker run with the same --name will keep failing until the leftover is started or removed.

Find the holder in two commands#

bash
# Containers publishing host port 8080, whatever their container port
docker ps --filter publish=8080 --format '{{.Names}}\t{{.Ports}}\t{{.Label "com.docker.compose.project"}}'

# Anything at all listening on 8080, with the owning process
sudo ss -ltnp 'sport = :8080'

The publish filter compares the host side of each mapping: Moby's daemon/list.go builds the key from PublicPort. In our test a container published as 127.0.0.1:18716:80 matched publish=18716 and did not match publish=80. The example in Docker's own CLI reference reads as if the filter matched the container port, so trust the test. A stopped container no longer appears, even with -a, which is consistent with it holding nothing.

ss needs sudo to show process names. A port owned by docker-proxy belongs to a container, and Docker publishes to 0.0.0.0 and [::] when no address is given, which the docs state and which showed up in our test as two docker-proxy listeners on the one port. For a UDP mapping, use -lunp instead of -ltnp.

The holder is usually your own old project#

The most common real cause is a Compose project that is still running under another name. Compose names a project after the directory that contains the compose file, unless -p, COMPOSE_PROJECT_NAME or a top-level name: says otherwise, in that order. Rename or copy the folder and docker compose up -d starts a second project beside the first:

text
Error response from daemon: failed to set up container networking: driver failed programming
external connectivity on endpoint stack-v2-web-1 (...): Bind for 127.0.0.1:18712 failed: port is already allocated

docker compose down in the new folder removed nothing of the old project. docker compose -p stack down, naming the old project, did, and the new one then started. The label in the docker ps command above prints the project name of whatever holds the port, so you know which -p to use. Pin a name: in every compose file, as Docker Compose conventions recommends, and a folder rename stops being a second deployment.

A restart loop can lose its port for good#

A container with restart: always that keeps crashing is not running between attempts, and during that gap it holds no port. We let one loop, started a second container on its port while it was down, and the looping container then failed to start with port is already allocated in its State.Error and stayed Exited. Docker's documentation describes always as restarting the container "if it stops", but a start that fails during network setup ended the loop: the container was still Exited 60 seconds later, and 30 seconds after we freed the port. Only a manual docker restart brought it back.

The practical version: an app that was crashing, and a second stack brought up on the same port while it was down, leaves the first app dead even after you remove the second. If something crashes in a loop for another reason, What Docker exit code 137 means covers the most common exit code.

Fixes, in the order to try them#

1. Stop the holder, if it is a leftover. docker compose -p <project> down for an old project, or docker rm -f <name> for a stray docker run container. Then retry. With Compose, docker compose up -d simply starts the container it left in Created state; in our test it came up on the second run with nothing else done. With docker run, either docker start the leftover or docker rm it first.

2. Change the left-hand number. The container side is never scarce: every container has its own network namespace, so twenty of them can listen on 8080 inside. Only the host side has to be unique. "8081:8080" ends the conflict. A host range such as 127.0.0.1:18713-18715:80 makes Docker take the first free port in it: with 18713 held, our container got 18714. That is useful for throwaway containers and confusing for anything you bookmark.

3. Bind to one address. 127.0.0.1:8080:8080 and 192.168.1.10:8080:8080 do not conflict with each other, which is how two services can share a port number on a host with two addresses. Remember that a 0.0.0.0 mapping on the same port blocks both. Binding to 127.0.0.1 also stops the port being reachable from the network, which matters because published ports skip your host firewall, as Why UFW does not block Docker ports shows.

4. Stop publishing. Behind a reverse proxy most services need no published port at all; the proxy reaches them by service name on a shared network, and nothing can collide. Reverse proxy and TLS has the layout, and Default port collisions lists which default ports the indexed tools fight over, led by 80, 8080, 443 and 3000.

Do not restart the Docker daemon as a first move. In every case we tested, the holder was a real, findable socket or container.

When this answer stops applying#

  • Engine 29 wording. The port is already allocated text is unchanged in the docker-v29.9.1 source. The kernel-side message changed shape there, to failed to bind host port 127.0.0.1:8080/tcp: address already in use, so match on the last words, not the whole line.
  • userland-proxy disabled. We tested only the default, where a docker-proxy process owns each published port. With "userland-proxy": false in daemon.json, check ss output before relying on that clue.
  • Docker Desktop, rootless Docker and Swarm. We did not test them. Everything above is Linux Engine running as root, with plain docker run and Compose.

What to do next#

Run docker ps --filter publish=<port> before anything else: if it names a container, that is your holder, and the Compose project label says how to stop it. If it names nothing, sudo ss -ltnp names the host process. To plan a stack without collisions in the first place, enter your services into the Port conflict checker. If the container you wanted to reach is a service on the host itself, that is a separate problem, covered in Reaching a host service from a container.

Questions#

Does a stopped container still hold its port?

No. In our tests on Engine 28.1.1, stopping a container released its published port at once, and a second container on the same address and port started immediately. A container that was only created, never started, held nothing either. The advice to run docker ps -a and remove stopped containers fixes the error only by coincidence, usually because the same command also brought down a running container from another Compose project.

What is the difference between port is already allocated and address already in use?

port is already allocated comes from Docker's own bookkeeping: another container already holds the identical host address and port. address already in use comes from the kernel when Docker tries to bind the socket, so the holder can be any process on the host, including another container published on an overlapping address, such as one on 0.0.0.0 while you ask for 127.0.0.1 on the same port.

Why does docker compose up fail with port is already allocated after I renamed the folder?

Because Compose names the project after the directory, so the renamed folder is a new project, and the old project's containers are still running with the port. docker compose down in the new folder does not touch them. Stop the old one with docker compose -p <old-name> down, then set a top-level name: in the compose file so the next rename cannot do it again.

How do I find which container is using a port?

Run docker ps --filter publish=8080. In Engine 28.1.1 that filter compares the host side of each mapping, so it finds the container publishing host port 8080, whatever its container port is, and it ignores stopped containers because they hold no host port. If it returns nothing, run sudo ss -ltnp 'sport = :8080': a docker-proxy owner means a container published on another address, anything else is a host service.

Can two containers publish the same port?

Yes, on different host addresses or different protocols. In our tests 127.0.0.1:18703 and 127.0.0.2:18703 coexisted, and so did a TCP and a UDP mapping on the same port. What cannot coexist is the same address twice, or 0.0.0.0 with any specific address on that port, because 0.0.0.0 means every address on the host.

Sources#

Published . Last reviewed . Found something out of date? Tell us and we will fix it and log the change.