环境搭建 · 2026年 9月 8日 0

Docker 端口绑定报错 “forbidden by its access permissions”:Windows + Hyper-V/WSL2 的保留端口坑

现象

docker compose up -d 启动一个映射了 3306 端口的容器,报错:

Error response from daemon: ports are not available: exposing port TCP 0.0.0.0:3306 -> 127.0.0.1:0:
listen tcp 0.0.0.0:3306: bind: An attempt was made to access a socket in a way forbidden by its access permissions.

第一反应是端口被占用,但排查后发现 netstat -ano | findstr :3306 并没有任何进程在监听。关键在于报错文案本身:forbidden by its access permissions(被访问权限禁止),这和端口占用的报错(address already in use)完全是两回事——这是 Windows 网络层的权限问题,不是程序冲突。

根本原因

开启了 Hyper-V 或 WSL2 的 Windows 系统,会动态地把一批 TCP 端口划入”保留范围”,分配给 Hyper-V 虚拟交换机使用。这些端口即使看起来没有任何程序在监听,外部程序(包括 Docker)也绑定不上。

查看当前的保留端口范围(需要管理员权限的终端):

powershell

netsh interface ipv4 show excludedportrange protocol=tcp

如果目标端口(比如 3306)恰好落在某一段范围里,就是这个问题。

解法一:重启 winnat 服务,刷新保留表

管理员权限的 PowerShell 或 CMD(注意:必须是独立打开的管理员终端,IDE 内置终端即使看起来是同一个窗口,也大概率不带管理员权限,执行会报”系统错误 5,拒绝访问”):

powershell

net stop winnat
net start winnat

之后重新 docker compose up -d。

如果还不行,可以试试重启 WSL 子系统:

powershell

wsl --shutdown

重启后重新打开 Docker Desktop 再试。

解法二:换一个不冲突的端口(更省心)

本地开发环境用哪个宿主机端口连接数据库并不重要,与其和 Windows 的动态端口保留机制反复较劲(这个坑就算这次修好了,重启电脑后也可能复发),不如直接换端口:

yaml

ports:
  - "13306:3306"

容器内部服务仍然监听标准端口(如 MySQL 的 3306),只是从宿主机连接时改用映射后的端口(如 127.0.0.1:13306)。零权限要求,零系统配置改动,基本一次成功。

小结

  • 看到 ports are not available 先别急着当成”端口占用”处理,报错文案里的 forbidden by its access permissions 指向的是系统权限问题,根源常常是 Windows 的动态端口保留。
  • 排查用 netsh interface ipv4 show excludedportrange protocol=tcp,命中范围就能确认。
  • 涉及系统服务的命令(net stop/start 等)必须在真正独立打开的管理员终端里执行。
  • 本地开发场景下,换一个空闲端口往往比死磕系统层面的权限问题性价比更高。