Docker Error Guide: 'bind: address already in use' — Port Conflict on Container Start
Fix 'bind: address already in use' in Docker: find the process or container holding the host port, free it or remap the published port, then restart.
- #docker
- #troubleshooting
- #errors
- #networking
Overview
Docker publishes a container port to the host by asking the kernel to bind() a listening socket on a host address and port. If something is already listening on that exact address:port, the kernel returns EADDRINUSE and Docker refuses to start the container. The message appears on docker run -p, docker start, or docker compose up:
Error response from daemon: driver failed programming external connectivity on endpoint web (a1b2...):
Bind for 0.0.0.0:8080 failed: port is already allocated
The lower-level variant surfaces the raw kernel error text:
docker: Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:8080 -> 0.0.0.0:0:
listen tcp 0.0.0.0:8080: bind: address already in use.
Symptoms
- A container exits immediately or never starts, and
docker ps -ashows it asCreatedorExited. docker compose upfails on one service while the rest come up.- The same image starts fine after you change the published host port.
docker start <container>fails even though it ran yesterday — because a second process grabbed the port in the meantime.
Common Root Causes
- Another container already publishes the same host port — a forgotten or duplicated
-p 8080:80. - A host process owns the port — a system nginx, a dev server, or a previously crashed app still holding the socket.
- Two Compose services map to the same host port — copy-paste in
docker-compose.yml. - A stopped container still holds the reservation — Docker’s userland proxy or a wedged
docker-proxyprocess kept the port allocated. - You restarted a service while the old instance was still shutting down, so both briefly want the port.
Diagnostic Workflow
First, ask Docker what it already has published:
docker ps --format 'table {{.Names}}\t{{.Ports}}'
Find the process actually listening on the host port (here 8080):
sudo ss -ltnp 'sport = :8080'
# or
sudo lsof -i :8080 -sTCP:LISTEN
If the listener is a container, inspect its port bindings:
docker inspect --format '{{json .NetworkSettings.Ports}}' <container>
If the process is docker-proxy, a container still owns the port — trace it back:
docker ps -a --filter "publish=8080"
Check daemon logs if the binding fails inconsistently:
journalctl -u docker --since '10 min ago' | grep -i 'bind\|already allocated'
Example Root Cause Analysis
A team reported Bind for 0.0.0.0:8080 failed: port is already allocated when running docker compose up api. docker ps showed no container on 8080, which pointed away from Docker. Running sudo ss -ltnp 'sport = :8080' returned:
LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=2417,fd=44))
A leftover Spring Boot dev process (PID 2417) from a manual test still held the port. It was not a container at all. Stopping that process with kill 2417 freed the socket, and docker compose up api succeeded immediately. The lesson: port is already allocated from Docker does not always mean another container — the conflict is at the host kernel level, so any host listener counts.
Prevention Best Practices
- Standardize host ports per environment and document them so two services never claim the same one.
- Bind to a specific interface (
-p 127.0.0.1:8080:80) for local-only services so they cannot collide with public listeners. - Prefer high, unique host ports in development and let a reverse proxy front them.
- In Compose, use variables like
${API_PORT:-8080}:80so conflicts are resolved by overriding one env var. - Always
docker compose down(not just Ctrl-C) so the old container releases its port before the next start. - Validate Dockerfiles and Compose port hygiene with the free Dockerfile validator.
Quick Command Reference
sudo ss -ltnp 'sport = :8080' # who holds the port
sudo lsof -i :8080 -sTCP:LISTEN # alternative lookup
docker ps --filter "publish=8080" # container publishing it
docker ps -a --filter "publish=8080" # including stopped ones
docker rm -f <container> # remove the conflicting container
docker run -p 8081:80 myapp:1.4.2 # remap to a free host port
Conclusion
bind: address already in use is a plain kernel EADDRINUSE: the host address:port you asked Docker to publish is already taken. Identify the real listener with ss/lsof, decide whether it is a container or a host process, then either free that port or remap your publish to an unused one. Standardizing ports and always tearing containers down cleanly keeps the conflict from returning. For more runtime fixes, see the Docker guides.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.