<p>PHP 8 连接 MySQL 8.0 必须用 mysqli 或 PDO,禁用已移除的 mysql_* 函数;需解决 caching_sha2_password 认证兼容性问题,显式设置 utf8mb4 字符集,并强制使用预处理语句防注入。</p>

PHP 8 连接 MySQL 8.0 必须用 mysqli 或 PDO,原生 mysql_* 函数在 PHP 7.0 已移除、PHP 8.0 完全不可用。直接写 mysqli_connect() 或 new mysqli() 就能连,但默认会失败——因为 MySQL 8.0 默认启用了 caching_sha2_password 认证插件,而旧版 mysqli(尤其未启用 mysqlnd 驱动时)不支持它。
MySQL 8.0 默认认证方式导致连接被拒绝
现象是报错:mysqli_connect(): The server requested authentication method unknown to the client [caching_sha2_password] 或类似提示。这不是密码错,是客户端根本不认识这个认证协议。
- 最稳妥的临时解法:登录 MySQL 8.0 后,为 PHP 使用的账号重置认证方式:
ALTER USER 'your_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password'; FLUSH PRIVILEGES;
- 长期方案:确保 PHP 编译时使用了
mysqlnd驱动(PHP 8.0+ 默认启用),它原生支持caching_sha2_password;可通过php -i | grep "mysqlnd"验证 - 不推荐改 MySQL 全局配置(如
default_authentication_plugin=mysql_native_password),会影响其他新应用
面向对象 vs 过程式:选哪一种写法更可靠
两者功能完全一致,但面向对象风格(new mysqli())在 PHP 8 中更易配合错误处理和类型提示。过程式(mysqli_connect())容易漏掉错误检查,比如忘记判断返回值是否为 false。
- 面向对象写法天然暴露连接状态:
$conn->connect_error直接可用,且可链式调用set_charset()、prepare() - 过程式必须显式传入连接资源句柄给每个函数,如
mysqli_query($link, $sql),一旦$link是false,后续调用会警告甚至 fatal - PHP 8.2+ 新增的
execute_query()方法只存在于面向对象接口中,无法在过程式里用
字符集设置必须在连接后立即执行
mysqli_set_charset($link, 'utf8mb4') 或 $conn->set_charset('utf8mb4') 不能省,也不能放在 SELECT 之后。MySQL 8.0 默认字符集是 utf8mb4,但 PHP 的 mysqli 初始化连接时仍可能沿用旧的 latin1,导致中文乱码或插入失败。
立即学习“PHP免费学习笔记(深入)”;
- 务必用
utf8mb4,不是utf8:后者在 MySQL 里只是utf8mb3的别名,不支持 emoji 和部分生僻汉字 - 如果用 DSN 方式(如 PDO),需在连接字符串里加
;charset=utf8mb4;但mysqli不支持 DSN,只能靠set_charset()显式设 - 设置失败时
set_charset()返回false,应检查,不能只依赖连接成功就认为字符集 OK
预处理语句是必须项,不是可选项
MySQL 8.0 对 SQL 注入更敏感,且 mysqli 在 PHP 8 下对未预处理的拼接查询会更早抛出警告(尤其开启 mysqli.report 时)。不用 prepare() + bind_param(),等于主动放弃基本安全防线。
- 过程式也要用:
$stmt = mysqli_prepare($link, $sql); mysqli_stmt_bind_param($stmt, 'si', $name, $id); - 面向对象更简洁:
$stmt = $conn->prepare($sql); $stmt->bind_param('si', $name, $id); - 注意参数类型符:
s(string)、i(integer)、d(double)、b(blob),传错会导致静默截断或类型转换错误
真正麻烦的不是连不上,而是连上了却因字符集、认证、预处理三者中任一环节疏漏,导致数据错乱、查询无声失败或安全漏洞——这些在开发机上常被忽略,上线后才爆发。



















