一、背景
今天又手欠在宝塔面板中将MySQL从5.4升级到8.0,升级完就一阵心慌,因为发现网站首页可以正常访问,但点击任何内页都会出现 Server Error(500 错误)。好在有AI,经过一番排查,终于解决了问题。当然如果解决不了也没关系,大不了重新装回旧版。现将完整的解决过程记录下来,后续再遇到类似问题可以自己解决,不用问AI走太多弯路。
二、问题现象
- ✅ 网站首页能正常打开
- ❌ 点击文章、分类、页面等任何内页,浏览器显示
Server Error或500 Internal Server Error - ❌ 宝塔面板的数据库恢复功能无效
- ❌ PHP-FPM 日志显示脚本执行超时
三、原因分析
MySQL 5.x 升级到 8.0 是一个跨大版本升级,变化较大,主要涉及以下几个方面:
| 问题类型 | 说明 |
|---|---|
| 身份认证插件变更 | MySQL 8.0 默认使用 caching_sha2_password,PHP 7.1 及以下版本不支持 |
| SQL 模式更严格 | 8.0 默认启用了 ONLY_FULL_GROUP_BY 等严格模式 |
| 默认字符集变更 | 8.0 默认字符集为 utf8mb4_0900_ai_ci,与旧版本不兼容 |
| 数据丢失 | ⚠️ 本次问题的核心原因:升级后数据库被删除或丢失 |
四、解决步骤
第一步:确认数据库是否存在
登录 MySQL,查看当前数据库列表:
mysql -u root -p
SHOW DATABASES;
预期结果:如果只看到以下 4 个系统数据库,说明业务数据库已丢失:
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
第二步:恢复数据库备份
2.1 检查备份文件位置
宝塔面板的数据库备份默认存放在:
ls -la /www/backup/database/
通常路径为:
/www/backup/database/mysql/你的数据库名/备份文件名.sql
2.2 创建空数据库
备份文件需要导入到一个已存在的数据库中,先手动创建数据库:
CREATE DATABASE 你的数据库名 CHARACTER SET utf8 COLLATE utf8_general_ci;
2.3 命令行恢复数据
⚠️ 重要提示:执行宝塔面板的”数据库恢复”功能失效,于是直接改用在命令行恢复。
方式一:直接导入 SQL 文件
mysql -u root -p 你的数据库名 < /www/backup/database/mysql/名称/备份文件路径.sql
方式二:导入压缩包(.gz)
gunzip -c 备份文件.sql.gz | mysql -u root -p 你的数据库名
方式三:强制导入(忽略错误)
mysql -u root -p --force 你的数据库名 < 备份文件.sql
2.4 验证数据完整性
恢复完成后,登录 MySQL 检查数据:
USE 你的数据库名;
SHOW TABLES;
SELECT COUNT(*) FROM 你的主表; -- 如 wp_posts、users 等
第三步:检查并修复用户认证插件
MySQL 8.0 默认使用 caching_sha2_password,可能导致 PHP 连接失败。
3.1 查看当前认证方式
SELECT user, host, plugin FROM mysql.user WHERE user='你的数据库用户名';
3.2 修改认证方式
如果 plugin 显示为 caching_sha2_password,执行以下命令修改:
ALTER USER '你的数据库用户名'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码';
FLUSH PRIVILEGES;
注意:如果
host不是localhost(如%或127.0.0.1),请相应修改。
示例:
ALTER USER 'wanghao'@'localhost' IDENTIFIED WITH mysql_native_password BY 'mypassword123';
FLUSH PRIVILEGES;
第四步:调整 SQL 模式(可选)
如果修改认证方式后仍然报错,检查 SQL 模式是否过于严格:
SELECT @@sql_mode;
如果包含 ONLY_FULL_GROUP_BY,可以临时放宽:
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
永久修改(修改配置文件):
vi /etc/my.cnf
在 [mysqld] 段落下添加:
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
保存后重启 MySQL:
/etc/init.d/mysqld restart
第五步:检查字符集
确认数据库字符集与程序兼容:
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME = '你的数据库名';
如有需要,修改数据库字符集:
ALTER DATABASE 你的数据库名 CHARACTER SET utf8 COLLATE utf8_general_ci;
第六步:重启 PHP-FPM 和 Nginx
完成所有修改后,重启服务使配置生效:
/etc/init.d/php-fpm-85 restart # 将 85 替换为你的 PHP 版本号
/etc/init.d/nginx restart
第七步:清除程序缓存
部分 PHP 框架会缓存数据库连接信息,需要清理缓存:
WordPress
- 方法一:后台安装 WP Optimize 插件清理缓存
- 方法二:清理 transient:
DELETE FROM wp_options WHERE option_name LIKE '%transient%';
五、查看错误日志
如果在以上步骤中遇到问题,可以通过错误日志定位具体原因:
PHP-FPM 错误日志
tail -50 /www/server/php/85/var/log/php-fpm.log
PHP-FPM 慢日志
tail -50 /www/server/php/85/var/log/php-fpm.log.slow
Nginx 错误日志
tail -50 /www/wwwlogs/你的域名.error.log
六、问题总结
MySQL 跨大版本升级(5.x → 8.0)是一个高风险操作,常见问题及解决方法如下:
| 问题类型 | 现象 | 解决方法 |
|---|---|---|
| 数据库丢失 | SHOW DATABASES; 看不到业务数据库 |
命令行恢复备份 |
| 认证插件不兼容 | PHP 无法连接 MySQL | 修改为 mysql_native_password |
| SQL 模式过于严格 | 某些 SQL 查询报错 | 移除 ONLY_FULL_GROUP_BY |
| 字符集不兼容 | 中文乱码或查询报错 | 修改为 utf8_general_ci |
| 程序缓存 | 修改后仍报错 | 清理缓存目录 |
| 服务未重启 | 配置未生效 | 重启 PHP-FPM 和 Nginx |
七、预防建议
升级前务必完整备份
- 宝塔面板自动备份
- 命令行手动导出备份
- 下载备份文件到本地电脑
做好云服务器快照
- 升级前为系统盘创建快照
- 出问题可秒级回滚
在测试环境先验证
- 大版本升级建议先在测试站尝试
- 确认无误后再操作生产环境
定期检查备份有效性
- 定期验证备份文件是否可以正常恢复
- 避免备份文件损坏导致无法恢复
记录数据库连接信息
- 数据库名、用户名、密码
- 用户 host(localhost / % / 127.0.0.1)
八 参考命令汇总
MySQL 相关命令
# 登录 MySQL
mysql -u root -p
# 查看所有数据库
SHOW DATABASES;
# 创建数据库
CREATE DATABASE 数据库名 CHARACTER SET utf8 COLLATE utf8_general_ci;
# 查看表
USE 数据库名;
SHOW TABLES;
# 查看数据量
SELECT COUNT(*) FROM 表名;
# 查看用户认证方式
SELECT user, host, plugin FROM mysql.user;
# 修改认证方式
ALTER USER '用户名'@'localhost' IDENTIFIED WITH mysql_native_password BY '密码';
FLUSH PRIVILEGES;
# 查看 SQL 模式
SELECT @@sql_mode;
# 修改 SQL 模式
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
# 查看字符集
SHOW VARIABLES LIKE 'character_set%';
数据库恢复命令
# 导入 SQL 文件
mysql -u root -p 数据库名 < /path/to/backup.sql
# 导入 gz 压缩文件
gunzip -c backup.sql.gz | mysql -u root -p 数据库名
# 强制导入(忽略错误)
mysql -u root -p --force 数据库名 < backup.sql
服务管理命令
# 重启 PHP-FPM(PHP 8.5)
/etc/init.d/php-fpm-85 restart
# 重启 Nginx
/etc/init.d/nginx restart
# 重启 MySQL
/etc/init.d/mysqld restart
错误日志查看命令
# PHP-FPM 错误日志
tail -50 /www/server/php/85/var/log/php-fpm.log
# Nginx 错误日志
tail -50 /www/wwwlogs/你的域名.error.log
# 实时监控日志
tail -f /www/server/php/85/var/log/php-fpm.log
九、成功标志
解决完成后,网站应该满足以下状态:
- ✅ 首页正常访问
- ✅ 所有内页正常访问
- ✅ 数据库查询正常
- ✅ 没有 500 错误
- ✅ PHP-FPM 日志无严重错误
十、结语
MySQL 跨大版本升级虽然风险较高,但只要按照正确的步骤操作,问题都是可以解决的。关键是要有完整的备份和清晰的排查思路。
正在等待第一条评论中