mysqli_connect()连接失败主因是环境或参数错误:MySQL服务未运行、端口非默认3306、localhost触发Unix socket而非TCP、用户认证插件不兼容(如MySQL 8+需mysql_native_password)、字符集未设utf8mb4、连接未复用或持久化滥用。

mysqli_connect() 连接失败的常见原因
直接调用 mysqli_connect() 却返回 false 或报错 “Connection refused”,通常不是代码写错了,而是环境或参数没对上。
- 检查 MySQL 服务是否真的在运行:
systemctl status mysql(Linux)或任务管理器里看mysqld进程 - 确认端口正确:默认是
3306,但 Docker 或 MAMP 等环境常改端口,连接时必须显式传入,比如mysqli_connect('127.0.0.1', 'root', 'pass', '', 3307) - 主机名别用
localhost:它会触发 Unix socket 连接,而很多 PHP 安装没配好 socket 路径;换成127.0.0.1强制走 TCP,更稳定 - 用户权限问题:MySQL 8+ 默认用
caching_sha2_password认证插件,老版本 mysqli 不兼容,建用户时得指定mysql_native_password,例如:CREATE USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd';
面向对象方式比过程式更推荐
虽然 mysqli_connect() 还能用,但实际项目中建议用面向对象写法,错误处理更自然、资源管理更清晰。
对比:
// 过程式(不推荐)
$conn = mysqli_connect('127.0.0.1', 'user', 'pass', 'db');
if (!$conn) {
die('Error: ' . mysqli_connect_error());
}
// 面向对象(推荐)
$conn = new mysqli('127.0.0.1', 'user', 'pass', 'db');
if ($conn->connect_error) {
die('Error: ' . $conn->connect_error);
}
- 对象方式可直接用
$conn->query()、$conn->prepare(),不用反复传连接句柄 - 支持异常模式:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);后,所有操作失败直接抛mysqli_sql_exception,不用手动判断返回值 - 注意:开启异常报告后,
new mysqli()失败也会抛异常,需用try/catch
连接后立刻设置字符集,否则中文变问号
即使数据库、表、字段都设了 utf8mb4,PHP 连接层不声明,照样乱码。这不是“存进去再读出来”的问题,而是连接建立那一刻就决定了传输编码。
立即学习“PHP免费学习笔记(深入)”;
- 面向对象方式:连接成功后立刻调用
$conn->set_charset('utf8mb4') - 过程式方式:用
mysqli_set_charset($conn, 'utf8mb4'),不能只靠SET NAMES utf8mb4查询来代替 - 验证是否生效:执行
SELECT @@character_set_client, @@character_set_connection, @@character_set_results,三个值都应为utf8mb4 - 跳过这步最典型的症状:插入正常,但
SELECT返回的中文字段全是???或空字符串
长连接和连接复用的实际影响
PHP-FPM 模式下,每次请求都是新进程,mysqli 连接天然不复用;但 CLI 或 Swoole 场景下,连接生命周期变长,得小心资源泄漏和超时。
- 不要在循环里反复
new mysqli():哪怕只是查几条数据,也应复用一个连接对象 - 避免用
p:前缀(如p:127.0.0.1)搞持久连接:PHP 的 mysqli 持久连接在 FPM 下效果有限,还可能因连接空闲超时被 MySQL 断开,导致后续查询报MySQL server has gone away - 如果用 Swoole,连接要绑定到协程上下文,且必须自己控制
close()时机,不能依赖脚本结束自动释放 - 连接超时由 MySQL 的
wait_timeout控制(默认 8 小时),但应用层最好加心跳或重连逻辑,尤其跨网络调用时











