docker: port is already allocated
Fix "port is already allocated": run docker ps and lsof -i :PORT to find the owner, then stop it or change the host port. Covers Compose and localhost binds.
docker: Error response from daemon: driver failed programming external
Incident Overview
Fix "port is already allocated": run docker ps and lsof -i :PORT to find the owner, then stop it or change the host port. Covers Compose and localhost binds.
easy fix·6 min read·3 causes
By Vishvesh Patel·DevOps Engineer·Updated 16 September 2026
docker: Error response from daemon: driver failed programming external connectivity on endpoint api (a3f2c1d4): Bind for 0.0.0.0:3000 failed: port is already allocated. Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:5432 -> 0.0.0.0:0: listen tcp4 0.0.0.0:5432: bind: address already in use
Do this first3 steps
Run these in order. Each one tells you what its output means before you change anything.
• Find out whether a container holds the port
Anything listed here owns the binding, running or exited. docker stop releases it; an exited container needs docker rm before the port comes back.
• If Docker shows nothing, it is a host process
Usually a local Postgres, another dev server or a system service. Stop that process, or publish on a different host port with -p 3001:3000.
• If you use Compose, check for another stack still up
Another project left its stack running. Change to that directory and run docker compose down. Stopping a single container leaves the rest of the stack and its network behind.
docker ps -a --filter "publish=3000" --format '{{.Names}}\t{{.Status}}'Then: the 3 causes in full
If the steps above did not settle it, these are the causes in the order they are usually responsible. Each section explains why it happens and how to confirm it.
The host port you asked Docker to publish is already bound by something. Docker cannot share a port, so the container refuses to start.
The owner is one of three things: another container, a stopped container Docker still has a reservation for, or an ordinary process on the host. Identifying which takes one command each.
Find the owner
Start with containers, since that is the usual answer:
If nothing there holds it, check the host:
A node, python or java process is a development server someone started outside Docker. docker-proxy means Docker itself still holds it. See below.
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' | grep 3000Cause 1: Another container
Compose users: a project left running from another directory is the classic case, because Compose namespaces containers by project but not host ports.
docker ps --filter "publish=3000" --format '{{.Names}}'
docker stop api-oldCause 2: A stopped container still holding the reservation
The confusing one. A container that exited can leave Docker's port mapping in place, so lsof shows docker-proxy with no running container to explain it:
docker stop is not enough here. The container must be removed. If removing it does not release the port, the daemon's networking state is stale:
On Docker Desktop, restart the application. That is a blunt instrument and it does resolve the case where nothing visible owns the port.
sudo lsof -i :3000
Cause 3: A host process
A locally installed PostgreSQL, MySQL, Redis or nginx conflicting with the containerised one. This is extremely common on developer machines, where 5432, 3306, 6379 and 80 are frequently taken by services installed years earlier.
Two options. Stop the host service:
Or, better, change the host port instead, so the two coexist:
Only the left-hand number changes. The container still listens on 5432 internally, so nothing inside it or in your Compose network needs adjusting.
sudo lsof -i :5432
Fixing it properly in Compose
Hardcoded host ports are what make this recur. Make them configurable:
Better still, do not publish ports you do not need from the host at all. Containers on the same Compose network reach each other by service name on the container port, so a database only needs publishing if you connect to it from your own machine:
That removes the conflict entirely and is closer to how the stack runs in production.
For throwaway containers, let Docker choose:
services:
api:
build: .
ports:
- "${API_PORT:-3000}:3000"
db:
image: postgres:17
ports:
- "${DB_PORT:-15432}:5432"Bind to localhost, not everything
Worth changing while you are here:
-p 3000:3000 binds 0.0.0.0, exposing the container to your whole network, and on Linux, Docker writes iptables rules that bypass ufw and firewalld, so a port you believed was firewalled is reachable from the LAN. Prefixing 127.0.0.1: limits it to your own machine.
docker run -d -p 127.0.0.1:3000:3000 myapp
A checklist
Frequently Asked Questions
How do I find what is using a port that Docker says is already allocated?
Two commands cover it. docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' shows every container including stopped ones and what each publishes. If none of them holds the port, sudo lsof -i :3000 or sudo ss -tlnp | grep :3000 names the host process. A result of docker-proxy means Docker itself still has a reservation, usually from a stopped container that has not been removed.
Why is a port still in use after I stopped the container?
Because stopping a container does not always release Docker's port reservation; removing it does. Run docker rm <name> rather than only docker stop. If the port is still held with no container to explain it, lsof showing docker-proxy, the daemon's networking state is stale and restarting Docker clears it. On Docker Desktop that means restarting the application.
How do I run a container when the host port is taken by a local service?
Change the host side of the mapping rather than stopping the service: docker run -p 15432:5432 postgres:17 publishes to 15432 while the container still listens on 5432 internally. Nothing inside the container or elsewhere on its Docker network needs to change, and you connect with psql -h localhost -p 15432. This is usually better than shutting down a locally installed database you may want later.
Why does Compose keep hitting port conflicts?
Because host ports are global while Compose projects are namespaced. Two projects can both try to publish 3000, and a stack left running from another directory holds it. docker compose ls lists every running project with its config file path, which finds the culprit immediately. Parameterise the host port as "${API_PORT:-3000}:3000" so it can be overridden, and stop publishing services that only other containers need.
Do I need to publish a database port in Compose?
Only if you connect to it from your own machine. Containers on the same Compose network reach each other by service name on the container port, so an API talks to db:5432 whether or not 5432 is published to the host. Removing the ports entry for internal services eliminates this class of conflict entirely and matches how the stack runs in production, where nothing exposes a database publicly.
Is -p 3000:3000 safe on a shared network?
Not especially. That form binds 0.0.0.0, making the container reachable from anything that can route to your machine, and on Linux, Docker inserts iptables rules ahead of ufw and firewalld, so a port you believe is firewalled is in fact open on the LAN. Use -p 127.0.0.1:3000:3000 to bind only the loopback interface, which is what you almost always want for local development.
Reference and practice
Learn the underlying concept
Other Docker errors
Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.
Get notified about new tutorials and features.
• Roadmaps
• Interview Prep
• Certifications
• Company
© 2026 DevOpsLesson. All rights reserved.
Need to practice this scenario?
Simulate this error condition and practice recovery commands safely in our in-browser terminal.