Docker化Web应用中PHP连接MySQL出现用户访问错误的解决方法
我正在构建一个需连接数据库实现登录功能的Web应用,目前已完成应用开发并进行容器化部署。将网站与数据库均部署在容器后,注册功能可正常运行,能将邮箱、姓名及密码存入MySQL数据库,但登录时出现如下错误:
Fatal error: Uncaught mysqli_sql_exception: Access denied for user 'my_user'@'172.31.0.3' (using password: YES) in /var/www/html/login.php:22 Stack trace: #0 /var/www/html/login.php(22): mysqli->__construct('db', 'my_user', Object(SensitiveParameterValue), 'database') #1 {main} thrown in /var/www/html/login.php on line 22
看起来my_user用户权限不足,但我已为该账号授予所有权限。
相关配置与代码
Docker镜像构建文件
FROM php:apache RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
Docker Compose配置
version: '3.8' services: web: image: web-db-0206 ports: - 80:80 volumes: - /home/user1/testwebdb:/var/www/html depends_on: - db db: image: mysql:5.7 ports: - 3306:3306 environment: - MYSQL_ROOT_PASSWORD=my_password - MYSQL_DATABASE=database - MYSQL_USER=my_user - MYSQL_PASSWORD=my_password volumes: - /home/user1/final_dockerfiles/website-database-test/db_data:/var/lib/mysql phpmyadmin: image: phpmyadmin/phpmyadmin ports: - 8080:80 environment: - PMA_HOST=10.174.80.3 restart: always volumes: db_data:
register.php代码
<?php $servername = "db"; $username = "my_user"; $password = "my_password"; $database = "database"; // 创建连接 $conn = new mysqli($servername, $username, $password, $database); // 检查连接 if ($conn->connect_error) { die("连接失败: " . $conn->connect_error); } // 检查表单是否提交 if ($_SERVER["REQUEST_METHOD"] === "POST") { // 获取表单数据 $email = $_POST["email"]; $name = $_POST["name"]; $password = $_POST["password"]; // 插入用户数据到数据库 $sql = "INSERT INTO users (email, name, password) VALUES ('$email', '$name', '$password')"; if ($conn->query($sql) === true) { echo "用户注册成功!"; } else { echo "错误: " . $sql . "<br>" . $conn->error; } } // 关闭连接 $conn->close(); ?> <!DOCTYPE html> <html> <body> <form action="register.php" method="POST"> <label>邮箱:</label> <input type="email" name="email" required><br><br> <label>姓名:</label> <input type="text" name="name" required><br><br> <label>密码:</label> <input type="password" name="password" required><br><br> <input type="submit" value="注册"> </form> </body> </html>
login.php代码
<?php session_start(); if (isset($_SESSION['user_id'])) { // 如果用户已登录,跳转到首页 header("Location: landing.php"); exit; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 数据库连接信息 $servername = "db"; $username = "my_user"; $password = "my_password"; $database = "database"; // 获取表单数据 $email = $_POST['email']; $password = $_POST['password']; // 创建连接 $conn = new mysqli($servername, $username, $password, $database); // 检查连接 if ($conn->connect_error) { die("连接失败: " . $conn->connect_error); } // 准备并绑定SQL语句 $stmt = $conn->prepare("SELECT id FROM users WHERE email = ? AND password = ?"); $stmt->bind_param("ss", $email, $password); // 执行语句 $stmt->execute(); // 存储结果 $stmt->store_result(); if ($stmt->num_rows === 1) { // 登录成功 $stmt->bind_result($user_id); $stmt->fetch(); // 将user_id存入session $_SESSION['user_id'] = $user_id; // 跳转到首页 header("Location: landing.php"); exit; } else { // 登录失败 $login_error = "邮箱或密码无效"; } // 关闭语句和连接 $stmt->close(); $conn->close(); } ?> <!DOCTYPE html> <html> <head> <title>登录页面</title> </head> <body> <h1>登录</h1> <?php if (isset($login_error)) { ?> <p><?php echo $login_error; ?></p> <?php } ?> <form action="login.php" method="POST"> <label>邮箱:</label> <input type="email" name="email" required><br><br> <label>密码:</label> <input type="password" name="password" required><br><br> <input type="submit" value="登录"> </form> </body> </html>
问题分析与解决方案
1. 用户权限范围不匹配
MySQL的用户权限是按用户名@来源IP划分的:注册功能正常说明my_user@db(容器内部域名解析的IP)有访问权限,但登录时报错的是my_user@172.31.0.3,说明该用户没有从这个IP访问的权限。
- 解决步骤:
- 进入MySQL容器:
docker exec -it <你的db容器ID> mysql -u root -p - 执行授权SQL:
此命令开放GRANT ALL PRIVILEGES ON database.* TO 'my_user'@'%' IDENTIFIED BY 'my_password'; FLUSH PRIVILEGES;my_user从任意IP访问目标数据库的权限,也可以将%替换为报错中的172.31.0.3来限制特定IP。
- 进入MySQL容器:
2. Docker网络一致性检查
确保web容器和db容器处于同一Docker网络:
- 查看容器IP:
确认两者在同一网段,且web容器能通过docker inspect <web容器名称> | grep IPAddress docker inspect <db容器名称> | grep IPAddressdb这个hostname解析到db容器。
3. 密码与配置一致性验证
通过phpmyadmin登录root账号,查看mysql.user表中my_user的权限配置、主机范围及密码是否与代码中的配置一致,避免容器初始化时的配置遗漏。
4. 数据库服务就绪等待
depends_on仅保证db容器先启动,不保证MySQL服务完全就绪。可以在web容器的启动脚本中添加等待逻辑,比如使用wait-for-it工具等待db的3306端口可用后再启动Apache服务。
内容的提问来源于stack exchange,提问作者lampi8426

