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:CONTAINER is already in use. Docker could not bind it, so the container was created but never started (docker ps -a shows it as Created).
  • Two wordings, same cause. Bind for 0.0.0.0:8080 failed: port is already allocated means 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 use means 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) or lsof -i :8080 (macOS). If the process is docker-proxy, docker ps --filter publish=8080 names the container.
  • Fix: use a free port (-p 8081:80), or stop whatever holds the port, then docker rm the half-created container and run again. In docker compose, change the ports: entry or docker compose down the other stack.
  • If nothing holds the port and it still fails, sudo systemctl restart docker clears a stale docker-proxy or iptables rule. Deleting local-kv.db by 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

  1. The error, reproduced, and what each part of it means
  2. Find out who holds the port
  3. Fix 1 - Start the container on a different port
  4. Fix 2 - Stop the container or process that holds the port
  5. Fix 3 - Restart the Docker daemon (stale docker-proxy or iptables)
  6. docker compose: the same error and the same fixes
  7. What broke when I ran this
  8. 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 messageMeaning
Bind for 0.0.0.0:8080 failed: port is already allocatedDocker'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 usethe 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 networkingthe 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 -

SystemCommandNotes
Linuxsudo 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 :8080net-tools package
macOSlsof -i :8080Docker 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
anydocker ps --filter publish=8080which container publishes the port

lsof showing the process that holds 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 -