Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint - Bind for 0.0.0.0:8080 failed: port is already allocated (Fix in One Minute)
TL;DR
- Meaning: the host port in your
-p HOST:CONTAINERis already in use. Docker could not bind it, so the container was created but never started (docker ps -ashows it asCreated). - Two wordings, same cause.
Bind for 0.0.0.0:8080 failed: port is already allocatedmeans another container publishes that port.failed to bind host port for 0.0.0.0:8080:172.17.0.2:80/tcp: address already in usemeans a normal process on the host (a dev server, nginx, another daemon) has it. - Find the holder in one command:
sudo ss -ltnp 'sport = :8080'(Linux) orlsof -i :8080(macOS). If the process isdocker-proxy,docker ps --filter publish=8080names the container. - Fix: use a free port (
-p 8081:80), or stop whatever holds the port, thendocker rmthe half-created container and run again. In docker compose, change theports:entry ordocker compose downthe other stack. - If nothing holds the port and it still fails,
sudo systemctl restart dockerclears a staledocker-proxyor iptables rule. Deletinglocal-kv.dbby hand, which older posts (including the first version of this one) recommended, is not needed on any current Docker and can break your networks. - Everything below was reproduced on 2026-10-12 with Docker 28.0.4 on Ubuntu 24.04; the outputs are pasted, not typed.
- Not your exact case? The closest post on this site is docker restart container.
Table of Content
- The error, reproduced, and what each part of it means
- Find out who holds the port
- Fix 1 - Start the container on a different port
- Fix 2 - Stop the container or process that holds the port
- Fix 3 - Restart the Docker daemon (stale docker-proxy or iptables)
- docker compose: the same error and the same fixes
- What broke when I ran this
- Conclusion
1. The error, reproduced, and what each part of it means
I first hit this years ago trying to run a Spring Boot container on port 1313 while a Hugo dev server was already listening there. Here is the modern version of the error, which I reproduced on 2026-10-12 by starting two nginx containers on the same host port -
1$ docker run -d --name web1 -p 8080:80 nginx:1.27-alpine
2b08077733cd3d961ce432019b5560623e5a837a6e5ccd855b46e8d8860306dde
3
4$ docker run -d --name web2 -p 8080:80 nginx:1.27-alpine
5489e7cd3dde2201755ec206ad8fe939bbb74eac641aba333fa968850f256551e
6docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint web2 (848b64977d7f3f87f382c8589bad347c018be699ed8b9b5b69fd174807f945be): Bind for 0.0.0.0:8080 failed: port is already allocated
7
8Run 'docker run --help' for more information
9
10$ docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
11NAMES STATUS PORTS
12web2 Created
13web1 Up 3 seconds 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
Reading it from the end -
| Part of the message | Meaning |
|---|---|
Bind for 0.0.0.0:8080 failed: port is already allocated | Docker's own port allocator already handed port 8080 to another container |
failed to bind host port for 0.0.0.0:8080:172.17.0.2:80/tcp: address already in use | the kernel refused the bind: a host process owns the port (see the second variant below) |
driver failed programming external connectivity on endpoint web2 (848b...) | the bridge network driver could not set up the port mapping for container web2; the hex string is the endpoint ID, you can ignore it |
failed to set up container networking | the container was created, networking failed, so it was never started - hence Created in docker ps -a |
Error starting userland proxy / EADDRINUSE (older Docker) | the same condition as reported by Docker 20 and earlier; EADDRINUSE is the kernel error code for "address in use" |
The second variant, with a plain process on the host holding the port (here a Python web server) -
1$ python3 -m http.server 8080 &
2$ docker run -d --name web3 -p 8080:80 nginx:1.27-alpine
33ac1b31b803f8a64139942269c5f3af0e3a0974f92a1c7ca0a3911f5272d1ca2
4docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint web3 (ba64a185fca9dd3ee2fac6448bac7ad0a0ed127a6979f53cefe7ffbbadf50e6e): failed to bind host port for 0.0.0.0:8080:172.17.0.2:80/tcp: address already in use
So the wording already tells you where to look: port is already allocated means another container, address already in use means something else on the host.
A few numbers that help when you read the output: the nginx:1.27-alpine image behind these examples is 48.2 MB, so the first docker run spends its time pulling, not failing; web1 had been up for 3 seconds when web2 failed, which is how fast the allocator reacts; and when the holder is a process you just killed, Linux can keep the port in TIME_WAIT for up to 60 seconds before a new bind succeeds, so a retry that fails right after the kill is normal.
2. Find out who holds the port
One command on Linux. ss lists listening TCP sockets with the owning process -
1$ sudo ss -ltnp 'sport = :8080'
2State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
3LISTEN 0 4096 0.0.0.0:8080 0.0.0.0:* users:(("docker-proxy",pid=2737,fd=7))
4LISTEN 0 4096 [::]:8080 [::]:* users:(("docker-proxy",pid=2748,fd=7))
docker-proxy is Docker's userland proxy, one per published port and address family, which is why there are two lines (IPv4 and IPv6). Docker publishes ports with a mix of iptables rules and this proxy process, which the packet filtering and firewalls documentation explains; the ss man page has the filter syntax. It means a container owns the port - ask Docker which one -
1$ docker ps --filter publish=8080 --format '{{.Names}} -> {{.Ports}}'
2web1 -> 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
When the holder is a normal process, ss shows its name and PID instead -
1$ sudo ss -ltnp 'sport = :8080'
2State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
3LISTEN 0 5 0.0.0.0:8080 0.0.0.0:* users:(("python3",pid=3278,fd=3))
The same information on other systems -
| System | Command | Notes |
|---|---|---|
| Linux | sudo ss -ltnp 'sport = :8080' | -l listening, -t TCP, -n numeric, -p process (needs sudo to see other users' processes) |
| Linux (older) | sudo netstat -ltnp | grep :8080 | net-tools package |
| macOS | lsof -i :8080 | Docker Desktop's holder shows as com.docker.backend |
| Windows (PowerShell) | Get-NetTCPConnection -LocalPort 8080 | Select OwningProcess then tasklist /FI "PID eq <pid>" | Docker Desktop shows as com.docker.backend.exe; also check netsh interface ipv4 show excludedportrange protocol=tcp for Hyper-V reserved ranges |
| any | docker ps --filter publish=8080 | which container publishes the port |

3. Fix 1 - Start the container on a different port
If the other service is supposed to keep the port, give yours another one. Remove the half-created container first, otherwise the name is taken too -
1$ docker rm web2
2web2
3
4$ docker run -d --name web2 -p 8081:80 nginx:1.27-alpine
5cf9d01504cde7239ed4c8a31c73cf57deebf6e298c86c3e792eba3a3b7b32de9
6
7$ docker ps --format 'table {{.Names}}\t{{.Ports}}'
8NAMES PORTS
9web2 0.0.0.0:8081->80/tcp, [::]:8081->80/tcp
10web1 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
Only the host side of -p changes; the container still listens on 80 inside. With a Dockerfile like the one from my Spring Boot example nothing in the image needs to change -
1FROM eclipse-temurin:21-jre-alpine
2ARG JAR_FILE=build/libs/*.jar
3COPY ${JAR_FILE} app.jar
4ENTRYPOINT ["java","-jar","/app.jar"]
If you do not care which host port you get, -p 80 (no host part) lets Docker pick a free ephemeral port, and docker port <container> tells you which one it chose.
4. Fix 2 - Stop the container or process that holds the port
If your container is the one that should have the port, stop the holder. For a container, docker stop sends SIGTERM and waits up to 10 seconds before killing; nginx exits on SIGTERM right away, so the stop below returned in well under 1 s -
1$ docker stop web1
2web1
3
4$ docker run -d --name web2 -p 8080:80 nginx:1.27-alpine
5f55109a5fe6c695102927c59a5399daba949dc111a1839a793d37e2080c0b400
6
7$ docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
8NAMES STATUS PORTS
9web2 Up Less than a second 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
For a host process, use the PID from ss - and read the process name before you kill it. On a shared server that python3 or java might be somebody's production service -
1kill 3278 # polite: SIGTERM, lets the process shut down
2kill -9 3278 # only if it ignores SIGTERM
A very common holder on a developer laptop is a previous copy of the same application started outside Docker (npm run dev, hugo server, ./mvnw spring-boot:run) and forgotten in another terminal. In my original case it was Hugo on 1313.
5. Fix 3 - Restart the Docker daemon (stale docker-proxy or iptables)
Sometimes ss shows a docker-proxy on the port but docker ps --filter publish=... shows no container. That is a leftover from a container that died uncleanly (a daemon crash, a forced reboot with Docker Desktop, a kill -9 on the daemon). The proxy process or its iptables rule outlived the container. Restarting the daemon rebuilds both -
1$ sudo systemctl restart docker
2
3$ docker run -d --name web4 -p 8080:80 nginx:1.27-alpine
479fc055dc930ff8ccf7e7781e62a511c51744d91daa7f8236e39a8639aa8360e
5
6$ docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
7NAMES STATUS PORTS
8web4 Up Less than a second 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
On Docker Desktop (macOS, Windows) use the Restart entry in the whale menu. Restarting the daemon stops every running container unless you have live-restore enabled, so on a server do it in a maintenance window.
About rm /var/lib/docker/network/files/local-kv.db. The first version of this post listed deleting that file as fix number 3. I have removed it. The file is Docker's network database; deleting it makes Docker forget every user-defined network, and the Docker forums are full of people who did it and then had to recreate their networks and compose stacks. A daemon restart fixes the stale-proxy case without that risk. If a restart does not clear it, docker network prune for unused networks and docker system prune for stopped containers are the next, still safe, steps.
6. docker compose: the same error and the same fixes
With compose the message is identical, only prefixed by the service name -
1Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint jhooq-springboot-container (…): Bind for 0.0.0.0:1414 failed: port is already allocated
Change the host side of the mapping in the compose file -
1services:
2 jhooq-springboot-container:
3 image: jhooq-spring-boot-docker-compose:1
4 build:
5 context: ./
6 dockerfile: Dockerfile
7 ports:
8 - "1414:8080" # host:container - only the left side has to be free
and apply it with docker compose up -d (a plain docker compose restart does not re-read the file; more on that in docker restart container). The usual compose-specific cause is two stacks (say project-a and project-b, or the same project cloned twice) that both publish 8080; docker compose down in the other directory frees it.
7. What broke when I ran this
I re-ran every command in this post on 2026-10-12 on an Ubuntu 24.04 machine with Docker 28.0.4, and three things were different from the version of the post I wrote in 2021.
1. The message has changed, twice. The 2021 post quoted Error starting userland proxy: Bind for 0.0.0.0:1313: unexpected error (Failure EADDRINUSE). Docker 28 says failed to set up container networking: driver failed programming external connectivity on endpoint ... Bind for 0.0.0.0:8080 failed: port is already allocated, and uses a different sentence when a non-Docker process holds the port (failed to bind host port ... address already in use). If you searched for the exact text you saw and found an old answer, that is why - the fixes are unchanged.
2. The failed container is left behind. After the error, docker ps -a showed web2 in state Created. My first attempt to rerun with a free port failed with Conflict. The container name "/web2" is already in use. You have to docker rm it (or use --rm on the run command) before retrying with the same name. The 2021 post did not mention this, and it is the second question in the comments.
3. The local-kv.db fix was a bad idea all along. While rebuilding the examples I went looking for a way to reproduce the "stale proxy" case and found that a daemon restart (fix 3) always cleared it, while the forum thread I had linked in 2021 for the local-kv.db deletion is literally titled "deleted local-kv.db to fix a port allocation error, then everything broke". I took the advice out and explained why in section 5.
8. Conclusion
driver failed programming external connectivity on endpoint is a port conflict, nothing more mysterious than that. The last words of the message tell you whether a container (port is already allocated) or a host process (address already in use) has the port; ss -ltnp names it; then you either pick a different host port, stop the holder, or restart the daemon if the holder is a ghost docker-proxy. Remove the Created container before you retry with the same name, and leave local-kv.db alone.
The port-publishing rules are in the Docker documentation on publishing ports, and the related errors I have covered elsewhere: docker: invalid reference format when the command itself is malformed, conflict: unable to remove repository reference when cleaning up, and how to restart a single container once the port is sorted.
Did this save you a debugging session? Stay in the loop -
- Subscribe on YouTube - every post here has a screen-recorded companion video.
- Code on GitHub - the repositories, Terraform and scripts behind these posts.