You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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访问的权限。

  • 解决步骤:
    1. 进入MySQL容器:
      docker exec -it <你的db容器ID> mysql -u root -p
      
    2. 执行授权SQL:
      GRANT ALL PRIVILEGES ON database.* TO 'my_user'@'%' IDENTIFIED BY 'my_password';
      FLUSH PRIVILEGES;
      
      此命令开放my_user从任意IP访问目标数据库的权限,也可以将%替换为报错中的172.31.0.3来限制特定IP。

2. Docker网络一致性检查

确保web容器和db容器处于同一Docker网络:

  • 查看容器IP:
    docker inspect <web容器名称> | grep IPAddress
    docker inspect <db容器名称> | grep IPAddress
    
    确认两者在同一网段,且web容器能通过db这个hostname解析到db容器。

3. 密码与配置一致性验证

通过phpmyadmin登录root账号,查看mysql.user表中my_user的权限配置、主机范围及密码是否与代码中的配置一致,避免容器初始化时的配置遗漏。

4. 数据库服务就绪等待

depends_on仅保证db容器先启动,不保证MySQL服务完全就绪。可以在web容器的启动脚本中添加等待逻辑,比如使用wait-for-it工具等待db的3306端口可用后再启动Apache服务。


内容的提问来源于stack exchange,提问作者lampi8426

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 04:12:42