PHP 7.0+ 中 mysql_connect() 已彻底移除,必须改用 mysqli 或 PDO;需显式设置 utf8mb4 字符集、启用预处理防注入,并验证连接可用性。

PHP 连接 MySQL 数据库,mysql_connect() 已彻底不可用——PHP 7.0+ 中该函数被移除,调用会直接报 Fatal error: Uncaught Error: Call to undefined function mysql_connect()。必须用 mysqli 或 PDO,且两者启用状态、字符集、错误处理方式稍有差异,选错或漏配就会卡在“连不上”或“查不出数据”上。
mysqli_connect() 报 Connection refused 怎么办
这不是 PHP 写错了,是底层连不上 MySQL 服务。常见原因和应对方式如下:
- MySQL 服务根本没运行:Linux 下执行
sudo systemctl status mysql,macOS 或 Windows 检查 MAMP/XAMPP 面板;没运行就先启服务 -
localhost在某些系统(尤其 macOS)会走 Unix socket 而非 TCP,导致端口不通;换成127.0.0.1更稳 - MySQL 配置了
bind-address = 127.0.0.1,但你用的是 Docker 或远程地址——确认my.cnf或mysqld.cnf中绑定地址是否匹配 - 端口不是默认 3306:XAMPP 默认 3306,MAMP 是 8889,Docker 容器可能映射为 3307;连接时必须显式传入端口号,例如
new mysqli('127.0.0.1', 'root', '', 'test', 3307)
mysqli 面向对象写法里 charset=utf8mb4 怎么设才生效
只在 DSN 或构造函数里写 charset=utf8mb4 不起作用——mysqli 的字符集必须单独调用 set_charset() 方法,否则中文、emoji 仍会乱码或被截断。
正确顺序是:
立即学习“PHP免费学习笔记(深入)”;
- 先创建连接:
$mysqli = new mysqli('127.0.0.1', 'root', '', 'testdb', 3306) - 再立即设置字符集:
$mysqli->set_charset('utf8mb4') - 检查是否成功:
if ($mysqli->connect_error) { ... }和if (!$mysqli->set_charset('utf8mb4')) { ... }都要判断
注意:set_charset() 必须在任何查询执行前调用,放在 query() 后面无效。
PDO 连接失败却没报错,为什么
PDO 默认不抛异常,SQL 错误或连接失败只会返回 false,而不会中断流程或输出提示——这是新手最常踩的坑。
必须手动开启异常模式:
- DSN 字符串里的
charset=utf8mb4是必需的,但仅用于初始化连接编码,不控制后续查询行为 -
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION必须作为选项传入构造函数,不能靠setAttribute()补救(因为连接失败时对象都创建不了) - 密码含
@、/、:等特殊字符时,DSN 解析会出错;建议改用环境变量读取,或 URL 编码处理,例如rawurlencode($password)
典型安全写法:
try {
$pdo = new PDO(
"mysql:host=127.0.0.1;dbname=testdb;charset=utf8mb4",
$_ENV['DB_USER'] ?? 'root',
$_ENV['DB_PASS'] ?? '',
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
} catch (PDOException $e) {
die('数据库连接失败:' . $e->getMessage());
}
mysqli 和 PDO 到底该选哪个
不取决于“哪个更高级”,而取决于你项目的真实约束:
- 只用 MySQL、代码量小、团队熟悉过程式风格 → 用
mysqli面向对象写法,PHP 默认启用,无需额外配置pdo_mysql - 需要未来换 PostgreSQL/SQLite、已有统一异常处理机制、或团队强推预处理 → 选
PDO,但务必确认extension=pdo_mysql在php.ini中已启用并重启服务 - 别为了“支持多库”硬上 PDO:如果永远只连 MySQL,PDO 的抽象层反而增加一层间接调用,且部分 MySQL 特有功能(如
mysqli_poll()、多语句执行)PDO 不支持
真正容易被忽略的是:无论用哪个,连接后都得执行一条 SELECT 1 来验证“连接可用”,而不仅是“对象创建成功”。很多线上问题出现在连接池空闲超时、防火墙自动断连等场景,光检查对象存在是不够的。



















