ports are not available: exposing port TCP 0.0.0.0:49400 ... bind: An attempt was made to
access a socket in a way forbidden by its access permissions. — Windows has reserved
that host port, so Docker cannot open it even though nothing is listening there. List the
reserved ranges with netsh and publish a port outside all of them.
No administrator prompt and no service restart are needed for this. Remove the container the failed run left behind and run it again with a host port that is not in any listed range; on this machine 15434 worked first time.
The error
$ docker run -d --name fix3-dpg-excl -e POSTGRES_PASSWORD=dev-only-password -p 49400:5432 postgres:18
7a3702d0740ff51c77b88cc86e7e5841c4041ea417afbcae8f5476d0b55f92f2
docker: Error response from daemon: ports are not available: exposing port TCP 0.0.0.0:49400 -> 127.0.0.1:0: listen tcp 0.0.0.0:49400: bind: An attempt was made to access a socket in a way forbidden by its access permissions.
Why it happens
Docker Desktop opens a published port on the Windows side itself; the message shows it
(listen tcp 0.0.0.0:49400). Windows keeps a list of TCP port ranges that programs
may not bind, and a bind inside one fails with this access-permissions error. It is not a
conflict with another program: Get-NetTCPConnection -LocalPort 49400 found nothing
on that port. The port is reserved, not in use.
This is the list on the machine that produced the error:
> netsh interface ipv4 show excludedportrange protocol=tcp
Protocol tcp Port Exclusion Ranges
Start Port End Port
---------- --------
80 80
49382 49481
49680 49779
50000 50059 *
57388 57487
57955 58054
58055 58154
58155 58254
60278 60377
61542 61641
* - Administered port exclusions.
Port 49400 sits in the first block of 100. Nine of the ten entries lie inside the Windows
dynamic port range, which netsh int ipv4 show dynamicport tcp reported as 16384
ports from 49152. The asterisk marks an administered exclusion; for the rest, netsh does not say
which program made the reservation, so this post does not guess. Your list will be your own,
so check it rather than copying port numbers from anywhere.
The fix
docker container rm fix3-dpg-excl
docker run -d --name fix3-dpg-excl -e POSTGRES_PASSWORD=dev-only-password -p 15434:5432 postgres:18
The failed run leaves the container in the Created state, so it is removed first.
The new one came up with 0.0.0.0:15434->5432/tcp, and psql connected
through it. In a compose file, change the left-hand side of the ports: entry the
same way. Removing or moving a reserved range needs an administrator prompt and changes the whole
machine; it was not tried here, and for a development container a different port is the simpler
answer.
How it was reproduced
Windows 11 (build 26200), Docker Desktop 4.91.0 with engine 29.8.0 on the WSL 2 backend, image
postgres:18 (18.4). netsh was run from a normal, non-elevated prompt
and listed the ranges above. A container publishing host port 49400, inside the 49382 to 49481
block, failed with the message above while nothing listened on that port. The same container
on 15434 started and accepted a psql connection from a client container through
host.docker.internal. No range was added, removed or changed. The name
fix3-dpg-excl is this test's own container; use yours.
Frequently asked
- How do I see which ports Windows has reserved?
- Run netsh interface ipv4 show excludedportrange protocol=tcp. It lists every excluded TCP range, marks administered exclusions with an asterisk, and works from a normal prompt without administrator rights.
- Why does Docker say ports are not available when nothing is using the port?
- Because the port is reserved, not used. Windows refuses a bind inside an excluded range even when no program listens there, and Docker Desktop reports that refusal as an access-permissions error.
- Do I need to restart winnat or change Windows settings to fix this Docker error?
- Not for a development container. Publishing a host port outside every listed range fixed it here without administrator rights or restarts. Changing reserved ranges or stopping services affects the whole machine and was not tested for this post.
More decoded errors in the Fixes category. When another container already publishes the port, Docker says port is already allocated instead.