先用mysql客户端直连验证TiDB服务状态,再启用PDO_MySQL扩展;ThinkPHP8连接需显式配置DSN并禁用自动charset追加,切换认证插件为mysql_native_password,初始化SQL清空sql_mode,确保mysqlnd版本≥8.0.22。

确认TiDB服务状态与连接基础
先验证TiDB是否真实可连,避免在PHP配置环节反复试错:用mysql客户端直连TiDB,执行mysql -h 127.0.0.1 -P 4000 -u root -p,输入密码后能进入mysql>提示符才算通;若报Can't connect to MySQL server,说明TiDB未启动或防火墙拦截,此时改PHP配置毫无意义。
PHP连接TiDB本质是走MySQL协议,所以必须确保PDO_MySQL扩展已启用:运行php -m | grep pdo_mysql,无输出则需编辑php.ini启用extension=pdo_mysql并重启PHP-FPM或Apache。
ThinkPHP8连接TiDB的PDO DSN写法
在.env中写DB_HOST=127.0.0.1、DB_PORT=4000后仍报1045,大概率是DSN拼接逻辑被框架自动补了?charset=utf8mb4导致TiDB拒绝——TiDB 6.0+虽支持该参数,但部分版本对URL编码敏感。
方法一:显式覆盖DSN(推荐)
在config/database.php中找到'connections' => ['mysql' => [...]]块,把'dsn'项设为完整字符串:
'dsn' => 'mysql:host=127.0.0.1;port=4000;dbname=test;charset=utf8mb4;connect_timeout=10';此写法绕过ThinkPHP自动拼接,【必须删除原有的host/port/database/charset等独立配置项,否则会冲突】。
立即学习“PHP免费学习笔记(深入)”;
方法二:禁用自动字符集追加
在同个mysql连接配置里加'strict' => false, 'options' => [\PDO::ATTR_EMULATE_PREPARES => true],再配合DB_CHARSET=utf8mb4环境变量,可抑制框架强行加charset参数的行为。
解决TiDB特有的认证插件不兼容
TiDB默认使用mysql_native_password认证,但某些部署启用了caching_sha2_password(尤其TiDB v7.5+集群模式),而PHP 8.0–8.2的PDO_MySQL对后者支持不稳定,连接时直接中断无明确报错。
第一步:登录TiDB执行SELECT user, host, plugin FROM mysql.user WHERE user = 'root';
第二步:若plugin列显示caching_sha2_password,立即切换回兼容模式:
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'your_password'; FLUSH PRIVILEGES;
第三步:如必须保留caching_sha2_password,则升级PHP至8.3+并确认PDO扩展编译时链接了新版MySQL Client Library(libmysqlclient >= 8.0.28)。
注意:TiDB的root@'%'和root@'localhost'是两个用户,【APP_ENV=production时ThinkPHP默认用TCP连接,必须匹配root@'%'而非root@'localhost'】。
处理TiDB不支持的SQL模式与语法
ThinkPHP8默认开启STRICT_TRANS_TABLES等严格模式,但TiDB对ONLY_FULL_GROUP_BY、NO_ZERO_DATE等MySQL特有模式识别不全,执行SHOW VARIABLES LIKE 'sql_mode';返回空或报错,进而触发PDO连接后自动SET失败。
在数据库连接配置中加入初始化SQL:
'options' => [\PDO::MYSQL_ATTR_INIT_COMMAND => "SET SESSION sql_mode = ''"]
这行代码必须放在config/database.php对应mysql连接的'options'数组内,不能写在.env里——因为.env只传字符串,无法承载PDO常量。
若仍报SQLSTATE[HY000]: General error: 1105 unknown error,检查是否用了TiDB不支持的语法:例如INSERT ... ON DUPLICATE KEY UPDATE在TiDB中需改用INSERT IGNORE或REPLACE INTO;FULLTEXT INDEX在TiDB中完全不可用,建表迁移时必须剔除。
验证PDO是否真正使用MySQL协议连接TiDB
在TP8控制器中插入调试代码:
$pdo = \think\facade\Db::getPdo(); var_dump($pdo->getAttribute(\PDO::ATTR_CLIENT_VERSION));
正常应输出类似mysqlnd 8.0.33或mysqlnd 8.2.12;若输出mysqlnd 7.4.33或为空,说明PHP加载的是旧版mysqlnd驱动,需重新编译PHP或更换二进制包。
执行php --ri pdo_mysql查看详细信息,重点核对Client API version是否≥8.0.22——低于此版本的mysqlnd对TiDB 7.x的事务一致性支持存在已知缺陷。



















