TechEarl

"Port is Already Allocated" / "Address Already in Use" in Docker

The two flavors of port conflict in Docker: another container is bound to it, or a host process is. How to find which, kill or relocate, and the -p syntax quirk that catches people.

Ishan KarunaratneIshan Karunaratne⏱️ 6 min readUpdated
Share thisCopied

docker run -p 5432:5432 postgres and back comes:

code
Error response from daemon: driver failed programming external connectivity on endpoint <name>: 
Bind for 0.0.0.0:5432 failed: port is already allocated

Or:

code
Error starting userland proxy: listen tcp4 0.0.0.0:5432: bind: address already in use

Same root cause: something else is bound to port 5432 on the host. That something is either another Docker container or a process on the host. The fix is to find it, then either kill it, change its port, or pick a different host port for the new container.

Find the offender

Is it another container?

bash
docker ps --filter publish=5432

That lists containers that have published port 5432. Usually one result. If found, that's your culprit:

bash
docker stop CONTAINER_ID
# or change its port and restart

Is it a host process? On Linux/Mac:

bash
sudo lsof -i :5432
# or
sudo ss -ltnp 'sport = :5432'

lsof shows: command name, PID, user, file descriptor, type, protocol, and the address. ss is the modern Linux replacement for netstat and shows similar info.

Once you have the PID, decide whether to stop the process:

bash
ps -p PID -o cmd=
# Confirm what it is before killing
sudo kill PID

On Windows (PowerShell):

powershell
Get-NetTCPConnection -LocalPort 5432 -State Listen | Select-Object OwningProcess
Get-Process -Id <PID>

Quick fix: pick a different host port

If you can't or don't want to free the original port, change the host port. The container port stays the same:

bash
docker run -d -p 5433:5432 postgres:17

Container port 5432 is unchanged; host-side, you reach Postgres on 5433. Connection string: postgres://...@127.0.0.1:5433/....

The -p HOST:CONTAINER order matters and trips people up. The container's port is on the right (which the container never changes). The host's port is on the left (which you choose). Mixing them up causes the container to bind on the wrong port and you to connect to the wrong one.

Bind to a specific interface

bash
docker run -d -p 127.0.0.1:5432:5432 postgres:17

Binds host port 5432 on loopback only — not on any other interface. Useful when port 5432 is "free" on loopback but already used on some external interface (rare, but happens on hosts with multiple network interfaces).

When two Docker installs fight

Sometimes there are two Docker daemons (rootful + rootless, or Docker Desktop + a separately-installed Docker Engine) and both try to claim the same port. docker ps only shows containers from the daemon your CLI is currently talking to. To check the other:

bash
# Rootless docker as your user
DOCKER_HOST="unix:///run/user/$(id -u)/docker.sock" docker ps --filter publish=5432

# Rootful docker
DOCKER_HOST="unix:///var/run/docker.sock" docker ps --filter publish=5432

If a container from the "other" Docker is the offender, stop it via that daemon.

Inside Docker Desktop's VM

On Mac and Windows, the port from your perspective is on the host, but Docker Desktop runs Linux in a VM and the actual port binding happens inside the VM. The error is the same; the diagnosis on the host (lsof, etc.) still works because Docker Desktop forwards the host port through to the VM.

Occasionally a Docker Desktop port binding gets stuck even after the container is gone. Fix:

  • Restart Docker Desktop.
  • If that fails, restart the host.

Stale binds are rare but happen.

Common scenarios

You started Postgres in Docker but already have Postgres on your host.

The host's Postgres binds 5432. The Docker container can't. Either:

  • Stop the host's Postgres (brew services stop postgresql, sudo systemctl stop postgresql, etc.).
  • Or run Docker's Postgres on a different host port: -p 5433:5432.

You restarted a Compose stack and got the error.

A previous container is still running or wasn't cleanly removed:

bash
docker compose down       # cleans up
docker compose up -d      # fresh start

If down doesn't remove the container (rare), docker rm -f $(docker ps -aq --filter name=projectname) does.

You ran docker run twice with the same -p.

The first container has the port. Stop it (docker stop CONTAINER_ID) before starting another on the same port, or use different host ports.

Port 80 / 443 conflict on macOS / Windows.

Local web servers (like a system Apache or IIS or a previously-installed nginx) often bind 80 already. Docker Desktop can't grab it. Stop the system service, or use a different host port like -p 8080:80.

Common pitfalls

  • Mixing up host:container order. It's -p HOST:CONTAINER. Container port is fixed by the image; host port is your choice.
  • Not realizing another container has the port. Run docker ps first.
  • Killing the offending process without identifying it. Use ps -p PID -o cmd= first to see what it is. It might be a daemon you want to keep, and a different host port is the right answer.
  • Port released but docker run still fails. Sometimes Linux's TIME_WAIT state holds a port for up to 60 seconds after it's released. Wait a minute and retry.
  • Docker Desktop stale bind. Restart Docker Desktop if a container died but the port still won't free.

What to do next

FAQ

Sources

Authoritative references this article was fact-checked against.

TagsDockerTroubleshootingPortsNetworkingDevOps

Found this useful? Pass it on.

Copied
Ishan Karunaratne

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

d

docker system prune: Free Disk Space Used by Docker

Docker fills up your disk. The prune commands clean it: docker system prune for the everyday sweep, docker system prune -a --volumes for the nuclear option, docker builder prune for the BuildKit cache, plus the per-resource versions.

Rank the biggest files on a full disk with find -printf '%s %p' piped to sort -rn. The GNU one-liner, the BSD stat variant for macOS, why -xdev matters, human-readable sizes, and when du or ncdu beats find.

How to Find the Largest Files on Disk (find, sort, du)

find / -xdev -type f -printf '%s %p\n' | sort -rn | head -20 gives you a ranked list of the biggest files on a full disk. The GNU one-liner, the BSD/macOS stat variant, why -xdev matters, human-readable output with numfmt, when to switch to du or ncdu for per-directory totals, and the mistakes that send a scan into /proc.