
本文详解 PHP 脚本无法连接 MySQL Docker 容器的典型原因:用户主机权限配置错误('user01'@'localhost' 无法匹配容器外 TCP 连接的真实客户端 IP),并提供完整、可复现的修复步骤与安全实践。
本文详解 php 脚本无法连接 mysql docker 容器的典型原因:用户主机权限配置错误(`'user01'@'localhost'` 无法匹配容器外 tcp 连接的真实客户端 ip),并提供完整、可复现的修复步骤与安全实践。
在 Docker 环境中,PHP 应用与 MySQL 容器之间的网络通信看似简单,实则暗藏关键细节——MySQL 用户授权的主机名(Host)必须精确匹配客户端发起连接时被识别的 IP 地址。您遇到的错误:
Access denied for user 'user01'@'10.10.10.10' (using password: YES)
是核心线索:MySQL 明确指出,当前连接来自 10.10.10.10(该 IP 实际为 Docker 桥接网络中宿主机的虚拟接口地址,常见于 docker0 或 br-xxxx 网络,具体值可通过 ip addr show docker0 查看),但您创建的用户 'user01'@'localhost' 仅允许从 容器内部 localhost(即 127.0.0.1 在 MySQL 容器内上下文)连接,完全不适用于宿主机 PHP 脚本通过 -p 52000:3306 映射发起的外部 TCP 连接。
✅ 正确解决方案:授权匹配真实客户端来源
您需在 MySQL 容器内执行以下操作(使用 mysql -h 127.0.0.1 -P 52000 -u root -ppassword123 连接后执行):
-- 1. 删除旧的、不生效的 localhost 用户(可选,避免混淆) DROP USER IF EXISTS 'user01'@'localhost'; -- 2. 创建或更新用户,主机部分必须为实际客户端 IP 或通配符 -- 方案 A(推荐):授权给宿主机在 Docker 网络中的确切 IP(如您的错误日志所示) CREATE USER 'user01'@'10.10.10.10' IDENTIFIED BY 'password123'; GRANT ALL PRIVILEGES ON myDB.* TO 'user01'@'10.10.10.10'; -- 方案 B(开发便捷):授权给任意 IP(仅限可信本地环境) CREATE USER 'user01'@'%' IDENTIFIED BY 'password123'; GRANT ALL PRIVILEGES ON myDB.* TO 'user01'@'%'; -- 3. 刷新权限使变更立即生效 FLUSH PRIVILEGES;
? 如何确认宿主机真实 IP?
在 Ubuntu 宿主机终端运行:ip -4 addr show | grep -A2 'docker0\|br-' | grep 'inet' | awk '{print $2}' | cut -d'/' -f1若输出为空,可临时使用 '%'(见方案 B),但生产环境务必限制为具体 IP 或子网。
立即学习“PHP免费学习笔记(深入)”;
✅ PHP 脚本修正要点
您的 PHP 代码逻辑基本正确,但需补充两点关键改进:
- 显式指定端口:mysqli_connect() 第五个参数为端口,您已传入 $mysqlPort,但原代码末尾缺少分号(语法错误);
- 增强错误诊断:捕获更详细的连接错误信息。
修正后的脚本如下:
<?php
$servername = "127.0.0.1";
$username = "user01";
$password = "password123";
$database = "myDB";
$mysqlPort = 52000; // ← 注意:此处应为整数,非字符串;且分号不可遗漏
// 创建连接(注意:第5个参数是端口,第6个是socket,传null即可)
$conn = mysqli_connect($servername, $username, $password, $database, $mysqlPort);
// 检查连接
if (!$conn) {
$error = mysqli_connect_error();
$errno = mysqli_connect_errno();
die("❌ 连接失败 [Errno $errno]: $error");
}
echo "✅ 连接成功!MySQL 版本:" . mysqli_get_server_info($conn) . "\n";
// 可选:验证数据库访问
if (mysqli_select_db($conn, $database)) {
echo "✅ 数据库 '$database' 访问正常。\n";
} else {
echo "⚠️ 警告:无法选择数据库 '$database' —— " . mysqli_error($conn) . "\n";
}
mysqli_close($conn);
?>⚠️ 重要注意事项与最佳实践
- localhost vs 127.0.0.1 的陷阱:在 MySQL 中,'user'@'localhost' 特指 Unix socket 连接,而 127.0.0.1 强制走 TCP。即使 PHP 连向 127.0.0.1,容器内的 MySQL 仍会将来源解析为宿主机在 Docker 网络中的 IP(如 10.10.10.10),绝非容器自身的 127.0.0.1。
- 避免 root 远程登录:切勿授予 root@'%' 权限。始终为应用创建专用用户,并遵循最小权限原则(例如仅授予 SELECT, INSERT, UPDATE 而非 ALL)。
- Docker 网络模式考量:若未来使用 --network host 启动 MySQL,则宿主 127.0.0.1:3306 直连容器,此时用户可设为 'user01'@'127.0.0.1';但默认 bridge 模式下,必须按桥接 IP 授权。
- 密码安全性:示例中明文密码仅用于调试。生产环境务必使用环境变量或配置管理工具注入凭据。
✅ 验证流程(三步闭环)
-
容器内验证授权:
SELECT User, Host FROM mysql.user WHERE User = 'user01'; SHOW GRANTS FOR 'user01'@'10.10.10.10'; -- 或 '@%'
-
宿主机网络连通性测试:
telnet 127.0.0.1 52000 # 应显示 Connected # 或 nc -zv 127.0.0.1 52000
-
执行 PHP 脚本:
php phpMySQL.php # 输出 ✅ 连接成功!...
至此,PHP 与 MySQL Docker 容器的连接问题将彻底解决。根本在于理解 Docker 网络模型下 MySQL 用户授权的“主机匹配”机制——它不是物理位置,而是 TCP 连接建立时 MySQL 服务端所感知的客户端源 IP。



















