Docker Compose "Port Already in Use": How to Fix
The Bind for 0.0.0.0:3000 failed: port is already allocated error means something else is already listening on that port. Here's how to find it and fix it.
- 1. Find the process:
lsof -i :3000(Mac/Linux) ornetstat -aon | findstr :3000(Windows) - 2. Stop it:
kill PID— or change your Compose host port - 3. Run
docker compose upagain
What the Error Looks Like
Docker Compose surfaces two common port error messages:
Both mean the same thing: the port you're trying to expose on the host is already bound to another process. Docker cannot claim a port that's already in use.
Step 1: Find What's Using the Port
On Mac / Linux
Output looks like:
The PID column (4521 in this example) is the process ID. The COMMAND column shows what's running. You can also use ss -tlnp | grep :3000 on Linux.
On Windows
Output looks like:
The last column is the PID. To find the process name:
Check for other Docker containers
A previous container might still be running in the background. Stop it withdocker stop CONTAINER_IDbefore running your compose command again.
Step 2: Three Ways to Fix It
Option A: Stop the conflicting process
Best when the conflicting process is a dev server you forgot was running. After stopping it, docker compose up should work.
Option B: Change the host port in docker-compose.yml
The port mapping format is HOST_PORT:CONTAINER_PORT. You only need to change the host side:
Your app inside the container still runs on port 3000. It's just exposed on port 3001 on your machine. Access it at http://localhost:3001.
Option C: Use environment variables for flexible port mapping
For teams where different developers may have different ports in use:
The {:-3000} syntax means "use HOST_PORT if set, otherwise default to 3000".
Special Cases
On Windows, the Port Proxy service (portproxy/hyper-v) can reserve port ranges. Check: netsh interface portproxy show all. Also check: netsh int ipv4 show excludedportrange protocol=tcp. If your port is in the excluded range, Docker can't use it. Use a different port.
The socket may be in TIME_WAIT state. This is normal TCP behavior — the OS holds the port for ~60 seconds after close. Either wait 60 seconds or use a different port temporarily.
You likely have a local installation of PostgreSQL or Redis running as a system service. On Mac: brew services stop postgresql@16. On Linux: sudo systemctl stop postgresql. Alternatively, map to a different host port: "5433:5432".
docker compose down stops and removes containers but if a container exited unexpectedly its port mapping may persist temporarily. Try: docker rm -f $(docker ps -aq) to force-remove all containers, then verify with docker ps -a.
Frequently Asked Questions
Why does Docker say a port is already in use when nothing is running?
Several causes: (1) A Docker container is running in the background — check with docker ps. (2) On Windows, Hyper-V or WSL2 reserves port ranges — check with netsh int ipv4 show excludedportrange protocol=tcp. (3) A process exited but its socket is still in TIME_WAIT state — wait 60 seconds. (4) A system service (PostgreSQL, Redis) is running — stop it or remap the port.
How do I prevent port conflicts in a team environment?
Use environment variables in docker-compose.yml: ports: ["${HOST_PORT:-3000}:3000"]. Each developer sets their HOST_PORT in a local .env file (which is gitignored). This way different developers can use different host ports without modifying the shared docker-compose.yml.
What is the difference between the host port and container port?
In Docker's port mapping "HOST:CONTAINER", the HOST port is what you use on your machine (localhost:HOST), and the CONTAINER port is what the application listens on inside the container. You can use any available HOST port to expose any CONTAINER port. For example, "8080:3000" means your app inside runs on 3000, but you access it via localhost:8080.
docker compose down vs docker compose stop — which frees the port?
Both stop containers and free ports. docker compose stop just stops the containers (they remain, can be restarted with docker compose start). docker compose down stops AND removes the containers. For port conflicts, either works. If ports remain allocated after stop, use docker compose down to fully remove containers.
Key Takeaways
- Port conflicts mean another process is already listening on that host port.
- Find the process with
lsof -i :PORT(Mac/Linux) ornetstat -aon | findstr :PORT(Windows). - Fix options: stop the conflicting process, change the host port in docker-compose.yml, or use env variables for flexible mapping.
- Common culprits: a forgotten dev server, a system PostgreSQL/Redis service, or a zombie Docker container.
- On Windows, check Hyper-V excluded port ranges with
netsh int ipv4 show excludedportrange protocol=tcp.