# Fix Docker "Port Is Already Allocated"

URL: https://www.devopsness.com/blog/fix-docker-port-already-allocated
Author: Kiril Urbonas
Published: 2026-07-09
Updated: 2026-10-12
Categories: DevOps
Tags: Docker, Networking, Containers, DevOps, Debugging

Summary: You run docker run, and it refuses to bind port 8080. Something already owns that port. Here is how to find the holder and get your container up.

---
# Fix Docker "Port Is Already Allocated"

Docker's "Bind for 0.0.0.0:8080 failed: port is already allocated" means another container or host process already owns that host port. Find the holder with `docker ps --filter publish=8080` (or `sudo ss -ltnp | grep :8080`), stop it, or publish to a free host port instead, for example `-p 8081:80`.

You run the container you have run a hundred times, and Docker throws this back:

```
docker: Error response from daemon: driver failed programming external
connectivity on endpoint web (a1b2c3...): Bind for 0.0.0.0:8080 failed:
port is already allocated.
```

Or the plain kernel version, which shows up when something outside Docker is holding the port:

```
Error starting userland proxy: listen tcp4 0.0.0.0:8080:
bind: address already in use
```

Both say the same thing. With `-p 8080:80`, Docker binds host port 8080 on every host address (`0.0.0.0` and `[::]`) to forward traffic to the container. If anything already owns 8080, the bind fails and the container never starts.

Note the shape of the mapping while we are here. `-p 8080:80` means host 8080 -> container 80. The number on the **left** is the one that fights over the host. The number on the right lives inside the container and never conflicts with anything on the host. Almost every "port is already allocated" error is about the left number.

## First, find who owns the port

There are two suspects: another Docker container, or a regular process on the host. Check Docker first because it is the fast one.

```bash
docker ps --filter publish=8080
```

That lists only containers publishing 8080. If you get a hit, there is your culprit:

```
CONTAINER ID   IMAGE       PORTS                    NAMES
7f9c1a2b3d4e   nginx       0.0.0.0:8080->80/tcp     old-web
```

Stop it and, if you do not need it, remove it:

```bash
docker stop old-web
docker rm old-web
```

Re-run your container. Done in most cases.

If `docker ps --filter publish=8080` comes back empty, the port is held by something that is not a running container. Two possibilities remain: a non-Docker process, or a stopped container that never got cleaned up. Time for the host-level tools.

```bash
sudo lsof -i :8080
```

```
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
node    18422 kiril  22u  IPv4  ...    0t0      TCP  *:http-alt (LISTEN)
```

On boxes without `lsof` installed, `ss` does the same thing and is usually already there:

```bash
sudo ss -ltnp | grep :8080
```

```
LISTEN 0  511  0.0.0.0:8080  0.0.0.0:*  users:(("node",pid=18422,fd=22))
```

There it is: a stray `node` dev server on PID 18422 that you left running three days ago, the single most common cause I see. On Docker Desktop for Mac, `lsof` may instead show `com.docker.backend`, which means a container (possibly in another Compose project or context) owns the port.

## Fix it: evict the holder or move your port

Once you know who holds the port, you have two honest options.

**Option A: kill the holder.** Reasonable when it is a leftover process you actually want gone.

```bash
kill 18422
# still there? it ignored SIGTERM, so:
kill -9 18422
```

Reach for `kill -9` only after a plain `kill` fails to clear it. Give the process a second to shut down before you go nuclear.

**Option B: move your container to a free host port.** This is the option I reach for most, because whatever is on 8080 is often something I want running too. Change only the host side of the mapping:

```bash
docker run -p 8081:80 nginx
```

Container still listens on 80 internally; you just reach it on `localhost:8081` from the host. Nothing inside the app changes. If you do not care which host port you get at all, let Docker pick one:

```bash
docker run -p 80 nginx
docker port <container>   # tells you which host port it grabbed
```

## The stopped-container trap

A container that is **stopped** but not **removed** keeps its port mapping in its config, and with a restart policy like `unless-stopped` it grabs the port again whenever the daemon restarts, often before your new container does. `docker ps` shows nothing because it only lists running containers. You need `-a`:

```bash
docker ps -a --filter publish=8080
```

```
CONTAINER ID   IMAGE   STATUS                    PORTS   NAMES
c5d6e7f8a9b0   web     Exited (0) 2 hours ago            web-old
```

Remove it and it can never reclaim the port:

```bash
docker rm web-old
```

If nothing at all shows up in `docker ps -a`, `lsof`, or `ss` and the error persists, the daemon's own port bookkeeping is stale, typically after a crash. `sudo systemctl restart docker` clears it.

## Compose leftovers and double-publishing

Two more that come up constantly.

If you run Docker Compose, an old stack from a previous branch or project may still be up, holding the port. The `docker ps` filter will show it, but the clean fix is to tear the whole stack down from the project directory:

```bash
docker compose down
```

That stops and removes every service the Compose file defined, which releases their ports in one shot. Beats hunting containers one by one.

The other self-inflicted one: publishing the same host port twice inside a single Compose file or a single `docker run`. Two services both asking for `8080:80` will fail the moment the second one starts. Grep your Compose file:

```bash
grep -n "8080:" docker-compose.yml
```

If you find two, one of them needs a different host port. This is also where `expose` versus `ports` confusion bites. `expose` only documents that a container listens on a port and makes it reachable to other containers on the same Docker network. It does **not** bind anything on the host and it never causes this error. Only `ports` (and `-p`) publish to the host, and only published ports can collide. If you were reaching for `expose` to fix an allocation error, you are in the wrong file.

For the broader map of what else goes wrong with containers, see our [Docker troubleshooting](/blog/docker-error-troubleshooting-guide) guide.

## Questions people ask

### What does "Bind for 0.0.0.0:8080 failed: port is already allocated" mean?

Docker tried to publish host port 8080 on all interfaces and found it taken. The `0.0.0.0` part just means "every IPv4 address on the host". The port number is the left side of your `-p` flag, so either free that port or choose a different one.

### How do I find which container is using a port?

Run `docker ps --filter publish=8080`, which lists running containers publishing or exposing that port. Add `-a` to include stopped ones. If neither finds anything, the holder is a regular process: use `sudo lsof -i :8080` or `sudo ss -ltnp | grep :8080` to get its PID.

### Can I bind the container only to localhost to avoid conflicts?

Binding to `127.0.0.1` with `-p 127.0.0.1:8080:80` limits who can reach the port, but it still collides with anything already listening on `127.0.0.1:8080` or `0.0.0.0:8080`. It is a security choice, not a conflict fix. To avoid conflicts, pick an unused host port.

## The call we'd make

Run `docker ps --filter publish=8080` first, every time. It answers the question in one line for the majority of cases, and it costs nothing. If it comes back empty, go straight to `sudo ss -ltnp | grep :8080` to catch the non-Docker holder, and do not forget `docker ps -a` for the stopped-container reservation. As for the fix: when the port belongs to something you also want running, remap your container to a free host port and move on. Killing processes to reclaim 8080 is a habit that eventually costs you the wrong process at the wrong time.

## Sources

- [Docker Docs: Port publishing and mapping](https://docs.docker.com/engine/network/port-publishing/)
- [Docker Docs: docker container ls (publish filter)](https://docs.docker.com/reference/cli/docker/container/ls/)
- [ss(8) Linux manual page](https://man7.org/linux/man-pages/man8/ss.8.html)

