根本原因是容器与宿主机网络隔离且mysql默认拒绝外部连接;容器内localhost指向自身,需改用host.docker.internal(win/macos)或配置bind-address=0.0.0.0、授权远程用户并开放防火墙。

根本原因不是“连不上”,而是容器和宿主机在不同网络平面,且 MySQL 默认拒绝外部 TCP 连接。
容器里写 localhost 实际连的是自己
这是最常踩的坑。Docker 容器启动后,localhost 指向容器内部的回环地址(127.0.0.1),而宿主机的 MySQL 服务根本不在这个容器里运行。
- Spring Boot 配置
jdbc:mysql://localhost:3306/mydb→ 容器内尝试连接自己 3306 端口,失败 - PHP 脚本用
mysqli_connect('localhost', ...)→ 同样走容器内部 socket/TCP,无服务监听 - 正确做法:把
localhost换成能指向宿主机的地址
host.docker.internal 是 Windows/macOS 的快捷解法
Docker Desktop 为 Windows 和 macOS 内置了 DNS 名 host.docker.internal,它会自动解析为宿主机的网关 IP(如 172.17.0.1)。
- Java/Go/Python 等应用中,把数据库 host 改成
host.docker.internal - Docker Compose 中可显式声明(避免 Linux 兼容问题):
extra_hosts: ["host.docker.internal:host-gateway"] - Linux 用户不支持该 DNS,默认不生效;若强行使用需手动添加
--add-host或改用--network=host
MySQL 本身默认只绑 127.0.0.1,拒绝外部连接
即使你用了正确的 host 地址(比如 192.168.1.100),如果宿主机 MySQL 的 bind-address 仍为 127.0.0.1,它会直接丢弃所有来自容器的 TCP 请求。
- 检查配置文件(Windows:
C:\ProgramData\MySQL\MySQL Server 8.0\my.ini;Linux:/etc/mysql/mysql.conf.d/mysqld.cnf) - 确认存在
bind-address = 0.0.0.0或至少bind-address = 192.168.1.100(非 127.0.0.1) - 改完必须重启 MySQL 服务:
sudo systemctl restart mysql或net stop mysql80 && net start mysql80 -
防火墙也要放行对应端口(Windows Defender /
ufw/ 云服务器安全组)
用户权限只允许 user@localhost,不认容器 IP
MySQL 的权限是按 'user'@'host' 组合判断的。你创建的 root@localhost 只接受 Unix socket 连接,对容器发来的 TCP 请求(来源 IP 如 172.17.0.1)完全无效。
- 登录宿主机 MySQL 执行:
CREATE USER 'myapp'@'%' IDENTIFIED BY 'mypass'; - 再授权:
GRANT ALL ON mydb.* TO 'myapp'@'%'; FLUSH PRIVILEGES; - 生产环境慎用
%,应明确限定来源 IP 段,例如'myapp'@'172.17.%' - 注意:
localhost在 MySQL 里是特殊值,不等于127.0.0.1,也不匹配任何 IP —— 它强制走本地 socket
真正卡住人的地方,往往不是单点问题,而是多个环节同时失效:容器配错 host、MySQL 没开 bind、用户没授远程权、防火墙又拦了一道。建议按「网络可达性 → MySQL 监听状态 → 权限匹配」顺序逐层验证,别一上来就调权限。











