php连接mysql乱码90%因未显式设置客户端字符集,应连接后立即用set_charset('utf8mb4')或dsn中指定charset=utf8mb4,并验证@@character_set_client等三值均为utf8mb4,同时确保php文件、http头、html meta均为utf-8。

PHP 连接 MySQL 时字符集出问题,90% 是因为没在连接建立后、执行 SQL 前显式设置客户端字符集,而不是只靠配置文件或建表时的 COLLATE。
连接时指定 charset 参数(推荐)
使用 mysqli 或 PDO 创建连接时,直接在 DSN 或连接参数中带上 charset=utf8mb4,这是最可靠的方式。
-
mysqli(面向对象):
$mysqli = new mysqli($host, $user, $pass, $db, $port, $socket); $mysqli->set_charset('utf8mb4'); -
mysqli(过程式):
$link = mysqli_connect($host, $user, $pass, $db); mysqli_set_charset($link, 'utf8mb4'); -
PDO(DSN 中声明):
$pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8mb4", $user, $pass, [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"])
避免只依赖 my.cnf 或 CREATE TABLE 的字符集
MySQL 配置文件里的 default-character-set=utf8mb4(或 character-set-server)只影响服务端默认值,不强制客户端行为;建表时写 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci 只管存储,不管传输过程。
- 即使表和字段都是 utf8mb4,若连接未设 charset,中文、emoji、生僻字仍可能变成
???或乱码 -
SET NAMES utf8不等于SET NAMES utf8mb4—— 后者才支持 4 字节 UTF-8 字符(如 ?、??)
验证当前连接字符集是否生效
连接建立后,执行一条查询确认实际使用的客户端编码:
立即学习“PHP免费学习笔记(深入)”;
SELECT @@character_set_client, @@character_set_connection, @@character_set_results;- 三者都应返回
utf8mb4;若出现latin1或utf8(注意不是 utf8mb4),说明设置未生效 - 也可用 PHP 检查:
var_dump($mysqli->character_set_name());或var_dump($pdo->getAttribute(PDO::ATTR_CLIENT_VERSION));(需结合 SQL 查看)
PHP 文件与 HTML 输出也要保持一致
数据库层设对了,但 PHP 脚本本身保存为 GBK、或输出 HTML 时没声明 <meta charset="UTF-8">,前端依然会显示异常。
- 确保 PHP 源文件以 UTF-8 无 BOM 格式保存
- HTTP 响应头建议加:
header('Content-Type: text/html; charset=utf-8'); - HTML 页面 head 中必须有:
<meta charset="UTF-8">
不复杂但容易忽略:字符集是端到端链条,缺一不可。连对、存对、读对、传对、渲染对,五步全走稳,乱码自然消失。











