使用 ProxySQL 桥接 PHP 5.6 与 MySQL 9.7 完整指南
适用场景:MySQL 9.7 + PHP 5.6 + PHPCMS,PHP 版本过低无法支持 MySQL 9.x 的
caching_sha2_password加密认证方式,需要引入 ProxySQL 作为认证中转层。
一、背景与原理
1.1 问题根因
| 组件 | 认识的加密方式 | 说明 |
|---|---|---|
| MySQL 9.7 | caching_sha2_password(默认) | 新版数据库只认新加密方式,且已移除 mysql_native_password 插件 |
| PHP 5.6 | mysql_native_password(仅此一种) | 老版本 mysqli 驱动不认识新加密方式,直连必报 2059/1045 |
两者语言不通,导致 PHP 5.6 无法直连 MySQL 9.7。
1.2 解决方案:ProxySQL 作为「翻译官」
┌──────────────┐ mysql_native_password ┌──────────────┐ caching_sha2_password ┌──────────────┐
│ PHP 5.6 │ ─────────────────────────▶ │ ProxySQL │ ────────────────────────▶ │ MySQL 9.7 │
│ PHPCMS │ TCP 127.0.0.1:6033 │ (中转层) │ TCP 127.0.0.1:3306 │ │
└──────────────┘ └──────────────┘ └──────────────┘前端(PHP → ProxySQL):ProxySQL 说
mysql_native_password,PHP 5.6 听得懂后端(ProxySQL → MySQL):ProxySQL 用
caching_sha2_password连 MySQL 9.7
1.3 ⚠️ 最关键的一条规则
ProxySQL 的 mysql_users 表里必须存明文密码(不能存预计算的 hash), 这样它才能分别给前端、后端计算各自认证方式需要的响应。
1.4 端口规划
| 端口 | 用途 | 谁能连 |
|---|---|---|
3306 | MySQL 9.7 本体 | ProxySQL 后端、管理工具 |
6032 | ProxySQL 管理口(配置用) | 管理员 |
6033 | ProxySQL 前端口(业务用) | PHP 5.6 / PHPCMS |
二、环境说明
操作系统:Debian 11(bullseye)
面板:宝塔面板(最新版)
数据库:MySQL 9.7(端口 3306,socket
/tmp/mysql.sock)PHP:5.6(宝塔
/www/server/php/56/)ProxySQL:2.6.5(Debian 11 专用包)
所有组件部署在同一台服务器(本机回环 127.0.0.1)
统一约定(文中出现的占位符,可按需整体替换):
- 中转账号用户名:
proxysql- 中转账号密码:
ProxySQL#Passwd
三、完整操作步骤
第 0 步:确认 MySQL 环境信息
先拿到后面配置要用的关键参数。
# 1. 确认 MySQL 版本与默认认证插件
/www/server/mysql/bin/mysql -uroot -p'你的ROOT密码' -e "
SELECT VERSION() AS ver;
SELECT @@default_authentication_plugin AS default_plugin;
SHOW VARIABLES LIKE 'socket';
SHOW VARIABLES LIKE 'port';
"必须确认的信息:
MySQL 版本是 9.x(
default_plugin为caching_sha2_password)socket 路径(宝塔默认
/tmp/mysql.sock)端口(默认
3306)
第 1 步:安装 ProxySQL
不用 apt 官方源(Debian 11 的官方源路径已 404),直接下载 deb 包安装最稳。
# 1.1 切到临时目录并下载(Debian 11 专用 amd64 包)
cd /tmp
wget https://github.com/sysown/proxysql/releases/download/v2.6.5/proxysql_2.6.5-debian11_amd64.deb -O proxysql.deb
# 若 GitHub 下载不动(国内常见),用加速镜像:
# wget https://ghfast.top/https://github.com/sysown/proxysql/releases/download/v2.6.5/proxysql_2.6.5-debian11_amd64.deb -O proxysql.deb# 1.2 安装(自动装依赖)
apt-get install -y ./proxysql.deb# 1.3 启动 + 设置开机自启
systemctl start proxysql
systemctl enable proxysql
sleep 3# 1.4 验证:6032 与 6033 两个端口必须都在监听
ss -tlnp | grep -E '6032|6033'预期输出:
LISTEN 0 4096 *:6032 *:* users:(("proxysql",pid=xxx,fd=x))
LISTEN 0 4096 *:6033 *:* users:(("proxysql",pid=xxx,fd=x))每条命令的作用:
| 命令 | 作用 |
|---|---|
wget ... -O proxysql.deb | 下载 ProxySQL 的 Debian 11 安装包 |
apt-get install -y ./proxysql.deb | 本地 deb 包安装,注册 systemd 服务 |
systemctl start proxysql | 启动 ProxySQL 服务 |
systemctl enable proxysql | 注册开机自启(重启后自动运行) |
ss -tlnp | grep -E '6032|6033' | 确认管理口(6032)和前端口(6033)已监听 |
第 2 步:安装低版本 MySQL / MariaDB 客户端(登录 ProxySQL 用)
⚠️ 为什么必须换客户端: MySQL 9.7 自带的
mysql客户端已经移除了mysql_native_password的客户端插件文件, 而 ProxySQL 管理口(6032)默认用mysql_native_password认证,导致报错:ERROR 2059 (HY000): Authentication plugin 'mysql_native_password' cannot be loaded: /usr/local/mysql/lib/plugin/mysql_native_password.so: cannot open shared object file因此需要安装一个仍支持旧认证插件的客户端,推荐 MariaDB 客户端。
# 2.1 安装 MariaDB 客户端(只装客户端,不影响已装的 MySQL 服务端)
apt-get install -y mariadb-client# 2.2 用 mariadb 客户端登录 ProxySQL 管理口(默认账号 admin / admin)
mariadb -uadmin -padmin -h127.0.0.1 -P6032 --prompt='ProxySQL> '预期结果: 进入 ProxySQL> 提示符即成功。
说明:
| 参数 | 含义 |
|---|---|
-uadmin | ProxySQL 管理口默认用户名为 admin |
-padmin | ProxySQL 管理口默认密码为 admin(首次安装) |
-h127.0.0.1 | 管理口在本机,用回环地址 |
-P6032 | 指定连管理端口 6032(不是 3306!) |
--prompt='ProxySQL> ' | 让提示符显示为 ProxySQL>,方便区分 |
说明:为什么不是 mysql 命令而是 mariadb 命令?
mysql(MySQL 9.7 自带)→ 不支持 mysql_native_password → 2059 错误mariadb(MariaDB 客户端)→ 完整支持 mysql_native_password 和 caching_sha2_password → 可以连
第 3 步:在 MySQL 9.7 中创建中转账号
ProxySQL 需要用它去连 MySQL 9.7 后端,所以 MySQL 里必须存在这个账号, 且必须使用 MySQL 9.7 认识的
caching_sha2_password插件。
# 3.1 用 root 创建 proxysql 用户
#(把单引号里的密码换成你的真实 ROOT 密码)
MYSQL_PWD='你的真实ROOT密码' /www/server/mysql/bin/mysql -uroot --protocol=SOCKET -e "
DROP USER IF EXISTS 'proxysql'@'localhost';
DROP USER IF EXISTS 'proxysql'@'127.0.0.1';
DROP USER IF EXISTS 'proxysql'@'%';
CREATE USER 'proxysql'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'ProxySQL#Passwd';
CREATE USER 'proxysql'@'127.0.0.1' IDENTIFIED WITH caching_sha2_password BY 'ProxySQL#Passwd';
GRANT ALL PRIVILEGES ON *.* TO 'proxysql'@'localhost' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO 'proxysql'@'127.0.0.1' WITH GRANT OPTION;
FLUSH PRIVILEGES;
SELECT user, host, plugin FROM mysql.user WHERE user='proxysql';
"预期输出(两行):
+----------+-----------+-----------------------+
| user | host | plugin |
+----------+-----------+-----------------------+
| proxysql | localhost | caching_sha2_password |
| proxysql | 127.0.0.1 | caching_sha2_password |
+----------+-----------+-----------------------+每条 SQL 的作用:
| SQL | 作用 |
|---|---|
DROP USER IF EXISTS 'proxysql'@'...' | 清理同名旧账号,避免 host 冲突导致匹配混乱 |
CREATE USER ... IDENTIFIED WITH caching_sha2_password BY '密码' | 创建中转账号,强制指定 MySQL 9.7 认识的加密插件 |
GRANT ALL PRIVILEGES ON *.* ... WITH GRANT OPTION | 授予全部数据库的权限(业务需要哪个库就授哪个,最小化可改为 库名.*) |
FLUSH PRIVILEGES | 立即生效授权 |
SELECT user, host, plugin ... | 验证账号、host、插件三要素是否就绪 |
为什么同时建
localhost和127.0.0.1? MySQL 对连接来源做反向解析:127.0.0.1常被解析成localhost。 两条都建、密码一致,无论匹配哪条都能通过。
# 3.2 验证 proxysql 能直连 MySQL 9.7(caching_sha2_password 认证)
MYSQL_PWD='ProxySQL#Passwd' /www/server/mysql/bin/mysql -uproxysql -h127.0.0.1 -P3306 --protocol=TCP \
-e "SELECT USER() u, @@version v;" 2>&1预期输出: u = proxysql@localhost + 版本号。此步必须通过才能继续。
第 4 步:配置 ProxySQL 中转
4.1 登录管理口
mariadb -uadmin -padmin -h127.0.0.1 -P6032 --prompt='ProxySQL> '4.2 配置后端服务器(ProxySQL → MySQL 9.7)
逐条粘贴以下 SQL(在 ProxySQL> 提示符下执行):
-- 4.2.1 清空旧的后端服务器记录
DELETE FROM mysql_servers WHERE 1=1;
-- 4.2.2 注册 MySQL 9.7 后端
INSERT INTO mysql_servers(hostgroup_id, hostname, port, comment, use_ssl, max_connections)
VALUES (0, '127.0.0.1', 3306, 'MySQL9x', 0, 500);
-- 4.2.3 保存到磁盘(重启不丢)
SAVE MYSQL SERVERS TO DISK;
-- 4.2.4 加载到运行时(不重启即生效)
LOAD MYSQL SERVERS TO RUNTIME;
-- 4.2.5 确认
SELECT hostgroup_id, hostname, port, status FROM mysql_servers;每条 SQL 的作用:
| SQL | 作用 |
|---|---|
DELETE FROM mysql_servers WHERE 1=1; | 清空默认示例后端,避免污染配置 |
INSERT INTO mysql_servers ... VALUES (0,'127.0.0.1',3306,...) | 注册真正的后端:0=主库组号,127.0.0.1:3306=MySQL 地址,use_ssl=0=本机内网不用 TLS |
SAVE MYSQL SERVERS TO DISK; | 把内存配置写入磁盘(/var/lib/proxysql/proxysql.db),重启后仍保留 |
LOAD MYSQL SERVERS TO RUNTIME; | 把磁盘/内存配置加载到正在运行的 ProxySQL,立即生效 |
SELECT ... status ... | 确认后端状态为 ONLINE(SHUNNED 说明被拉黑,见排查) |
ProxySQL 三层配置模型: 内存(Runtime) → 内存(Memory) → 磁盘(Disk)。 任何修改必须
SAVE ... TO DISK+LOAD ... TO RUNTIME才完整生效。
4.3 配置用户(前端 PHP 5.6 认 proxysql)
-- 4.3.1 清空旧用户(避免残留)
DELETE FROM mysql_users WHERE username='proxysql';
-- 4.3.2 注册前端用户(⚠️ 密码必须填明文!)
INSERT INTO mysql_users(
username, password, active, use_ssl,
default_hostgroup, default_schema,
transaction_persistent, fast_forward,
backend, frontend, max_connections, comment
) VALUES (
'proxysql', 'ProxySQL#Passwd', 1, 0,
0, 'yhz_lgrhyy2',
1, 1, 1, 1, 500, 'bridge'
);
-- 4.3.3 保存 + 加载
SAVE MYSQL USERS TO DISK;
LOAD MYSQL USERS TO RUNTIME;
-- 4.3.4 确认(重点看 password 是不是明文)
-- ⚠️ ProxySQL 管理口底层是 SQLite,不支持 MySQL 的 LEFT(),必须用 substr()
SELECT username, active, default_hostgroup, default_schema,
substr(password, 1, 15) AS pw_preview, LENGTH(password) AS pw_len,
fast_forward, comment
FROM mysql_users WHERE username='proxysql';每条 SQL 的作用:
| SQL | 作用 |
|---|---|
DELETE FROM mysql_users WHERE username='proxysql'; | 清理同名用户(用户名是主键,不能重复) |
INSERT INTO mysql_users(...) VALUES('proxysql','ProxySQL#Passwd',...) | 注册中转用户。password 必须明文;default_hostgroup=0 走主库组;default_schema 占位(各业务库自行 USE);fast_forward=1 直通模式,性能最优 |
SAVE MYSQL USERS TO DISK; / LOAD MYSQL USERS TO RUNTIME; | 持久化 + 立即生效 |
SELECT ... substr(password,1,15) ... | 验证密码是否为明文(若显示 *6BB4... 说明存成了 hash,必须重写)。注意:管理口是 SQLite,用 substr() 而非 MySQL 的 LEFT() |
⚠️ 密码必须和 MySQL 侧 CREATE USER 时的密码一字不差(含大小写、特殊字符)。这就是「直连 MySQL 能通,但走 ProxySQL 就 1045」的最常见原因:两边密码不一致。
退出管理口:
EXIT;第 5 步:验证全链路
5.1 模拟 PHP 5.6(强制用 mysql_native_password 登录前端口 6033)
MYSQL_PWD='ProxySQL#Passwd' mariadb -uproxysql -h127.0.0.1 -P6033 --protocol=TCP \
--default-auth=mysql_native_password -e "SELECT USER() u, @@version v;" 2>&1预期输出: u = proxysql@localhost + MySQL 版本号 → 桥接成功。
| 参数 | 含义 |
|---|---|
--protocol=TCP | 强制走 TCP(避免 localhost 被转成 socket) |
--default-auth=mysql_native_password | 强制用旧插件,模拟 PHP 5.6 的认证行为。加了这参数能连,PHP 5.6 也必能连 |
5.2 逐个验证业务库(权限验证)
MYSQL_PWD='ProxySQL#Passwd' mariadb -uproxysql -h127.0.0.1 -P6033 \
-e "USE 库名1; SELECT 'OK' AS r;" 2>&15.3 PHP 5.6 最终验收
/www/server/php/56/bin/php -r '
$l=@mysqli_connect("127.0.0.1","proxysql","ProxySQL#Passwd","你的库名",6033);
if($l){echo "OK host=".mysqli_get_host_info($l)."\n";$r=mysqli_query($l,"SELECT USER() u");$w=mysqli_fetch_row($r);echo "USER=".$w[0]."\n";mysqli_close($l);}
else{echo "FAIL ".mysqli_connect_errno()." ".mysqli_connect_error()."\n";}
'预期输出: OK host=127.0.0.1 via TCP/IP + USER=proxysql@localhost → 通关。
第 6 步:修改 PHPCMS 配置
每个站点的 caches/configs/database.php:
<?php
return array (
'default' => array (
'hostname' => '127.0.0.1', // ProxySQL 在本机
'port' => '6033', // ★ 必须指向 ProxySQL 前端口,不是 3306!
'database' => '你的库名', // 每个站改成自己的库名
'username' => 'proxysql', // 和 ProxySQL mysql_users 一致
'password' => 'ProxySQL#Passwd', // 明文,同上
'tablepre' => 'v9_',
'charset' => 'gbk',
'type' => 'mysqli',
'debug' => true,
'pconnect' => 0,
'autoconnect' => 0,
'socket' => '', // 留空,走 TCP 到 6033
),
);配置项说明:
| 配置项 | 说明 | 易错点 |
|---|---|---|
hostname | 填 127.0.0.1 | 别填 localhost,避免 PHP 自动转 socket 造成 host 匹配错乱 |
port | 填 6033 | 最易错:仍写 3306 会直连 MySQL 被 caching_sha2 拒绝 |
database | 每个站自己的库名 | 必须和库名一字不差,否则 1044 |
username / password | 中转账号 | 必须和 ProxySQL/MySQL 侧完全一致 |
type | mysqli | PHPCMS 必须用 mysqli 驱动 |
socket | 留空 | 走 TCP,不要配 socket |
清空 PHPCMS 缓存:
cd /www/wwwroot/你的站点目录/
rm -rf caches/cache_* caches/tpl_cache/* caches/model_cache/*然后访问前台/后台测试。
四、常见问题排查
| 现象 | 原因 | 处理 |
|---|---|---|
2059 ... mysql_native_password cannot be loaded | 用了 MySQL 9.7 自带客户端连 ProxySQL | 换 mariadb 客户端(第 2 步) |
1045 Access denied ... using password: YES | ProxySQL mysql_users 密码 ≠ MySQL 真实密码 | 两边密码统一;SAVE + LOAD 后重测 |
1044 Access denied to database 'xxx' | proxysql 用户没有该库权限 | root 补授权:GRANT ALL ON 库名.* TO 'proxysql'@'...' |
2003 Can't connect | 6033 没监听 / 防火墙拦了 | ss -tlnp | grep 603;宝塔安全放行 6033(仅内网) |
status=SHUNNED | 后端曾连续认证失败被临时拉黑 | 登 6032:UPDATE mysql_servers SET status='ONLINE'; LOAD MYSQL SERVERS TO RUNTIME; |
| PHPCMS 报 caching_sha2 不认 | PHPCMS 仍连 3306 | 改 port => '6033' |
| 一个库通、其他库不通 | 其他库缺权限 或 该站配置没改 | 按 5.2 逐个 USE 验证;按第 6 步核对 database.php |
五、安全加固(可选但推荐)
5.1 修改 ProxySQL 管理口默认密码
默认 admin/admin 有风险,登录管理口后:
UPDATE global_variables SET variable_value='admin:你的新管理密码' WHERE variable_name='admin-admin_credentials';
SAVE ADMIN VARIABLES TO DISK;
LOAD ADMIN VARIABLES TO RUNTIME;之后用 mariadb -uadmin -p'新密码' -h127.0.0.1 -P6032 登录。
5.2 防火墙只允许本机访问 6032/6033
iptables -A INPUT -p tcp --dport 6032 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 6033 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 6032 -j DROP
iptables -A INPUT -p tcp --dport 6033 -j DROP
netfilter-persistent save5.3 日常运维命令
systemctl status proxysql --no-pager # 查看服务状态
systemctl restart proxysql # 重启
journalctl -u proxysql -n 50 --no-pager # 看日志
tail -50 /var/lib/proxysql/proxysql.log # 看 ProxySQL 日志六、总结(核心要点)
- PHP 5.6 连不上 MySQL 9.7 是认证插件不兼容,不是网络/密码问题。
- ProxySQL 中转让前端说旧协议、后端说新协议,业务代码零改动。
- ProxySQL
mysql_users必须存明文密码,且与 MySQL 账号密码一字不差。 - 连 ProxySQL 管理口必须用老客户端(如
mariadb),MySQL 9.7 自带客户端不行。 - PHPCMS 的 port 必须是 6033,不是 3306。
- 所有密码、用户名、库名保持三处一致:MySQL、ProxySQL、PHPCMS。
