Appearance
15|常见故障排查
前面 14 篇讲了怎么装、怎么用、怎么优化。但实际运维里 MySQL 出问题,往往就是几个固定的类型:起不来、连不上、磁盘满、字符集乱、跑得慢。
本篇把这些常见故障的排查套路集中讲。复制异常在第 13 篇、慢查询在第 7 篇讲过,这里不重复,聚焦启动、连接、磁盘、字符集这几类。
一、错误日志是第一站
不管什么故障,先看错误日志。它比 systemd 的状态更具体:
sql
SHOW VARIABLES LIKE 'log_error';bash
tail -n 200 /data/mysql/logs/error.log
# systemd 环境
journalctl -u mysqld -n 100 --no-pagersystemd 只显示 Failed with exit-code,错误日志里能看到具体原因——unknown variable、Permission denied、bind on TCP/IP port failed。先看错误日志,再动手。
二、启动失败
systemctl start mysqld 失败。常见原因和排查:
| 原因 | 错误日志特征 | 排查 |
|---|---|---|
| 配置参数写错 | unknown variable 'xxx' | 检查 my.cnf 拼写 |
| 目录权限不对 | Permission denied | 看数据目录属主 |
| 数据目录不存在 | datadir 相关错误 | 确认 datadir 路径 |
| 端口被占用 | bind on TCP/IP port failed | ss -lntp | grep 3306 |
| 磁盘满 | No space left on device | df -h + df -ih |
| redo/undo 损坏 | 错误日志有具体信息 | 看日志判断能不能修 |
检查关键路径和权限:
bash
# 看配置里的路径
grep -E 'datadir|log_error|socket|pid-file|tmpdir' /etc/my.cnf
# 确认目录权限(mysql 用户要有读写权限)
ls -ld /data/mysql /data/mysql/data /data/mysql/logs
# 修正权限
chown -R mysql:mysql /data/mysql
# 端口是否被占
ss -lntp | grep ':3306'chown -R 前确认路径别打错——打错了 chown -R mysql:mysql / 就是灾难。先 pwd、ls -ld 确认再执行。
磁盘满要分两种:df -h 看数据盘空间,df -ih 看 inode 是否用完(小文件太多会耗尽 inode,空间还有但建不了文件)。
三、连接失败
连不上 MySQL。分几层排查:
bash
# 1. 网络层——端口通不通
nc -vz mysql_host 3306
ss -lntp | grep ':3306' # 服务端看端口在不在
# 2. 本地 socket 连(绕过网络层)
mysql -uroot -p --socket=/data/mysql/tmp/mysql.socksocket 能连但 TCP 不能——bind_address 限制了监听地址:
sql
SHOW VARIABLES LIKE 'bind_address';默认 * 监听所有地址。如果配成了 127.0.0.1,远程连不上——只允许本机。
Access denied
连上了但认证失败:
text
ERROR 1045 (28000): Access denied for user 'app'@'10.0.1.5'排查方向:
- 密码对不对
- 账号存在不存在:
SELECT user, host FROM mysql.user WHERE user='app' - host 匹配对不对(第 11 篇讲过 user@host 匹配)
- 账号有没有被锁:
account_locked
第 11 篇讲的 USER() vs CURRENT_USER() 在这里用——看实际匹配到哪个账号。
Too many connections
text
ERROR 1040 (HY000): Too many connections连接数打满。第 10 篇讲过——不是无脑调大 max_connections,要看连上来的人在干什么。但当下连不进去处理不了,可以留一个管理连接:
ini
# my.cnf
max_connections=500
admin_port=33062 # 额外管理端口,不占普通连接配额admin_port 是给 root 的专用连接端口,连接打满时也能连进去排查。
四、磁盘空间
磁盘满会导致 MySQL 写不了、起不来。常见占用大户:
bash
# 看数据目录占用
du -sh /data/mysql/* | sort -hr
# 看 binlog 占了多少
du -sh /data/mysql/logs/mysql-bin*
# 看慢日志、错误日志
du -sh /data/mysql/logs/*.logbinlog 是常见占用大户——binlog_expire_logs_seconds 设太长,binlog 堆着不清。看 binlog 列表和最早时间:
sql
SHOW BINARY LOGS;清理过期的(确认从库不需要了才删):
sql
PURGE BINARY LOGS BEFORE '2026-06-01';或者调短保留时间(重启后对新增 binlog 生效):
ini
binlog_expire_logs_seconds=259200 # 3 天别在生产主库乱 RESET MASTER——会清掉所有 binlog,从库复制直接断。
五、字符集问题
存中文或 emoji 出现乱码、???、或存不进去报错:
sql
-- 看库的字符集
SELECT default_character_set_name FROM information_schema.schemata WHERE schema_name='app_db';
-- 看表的字符集
SELECT table_name, table_collation FROM information_schema.tables WHERE table_schema='app_db';
-- 看字段的字符集
SELECT column_name, character_set_name FROM information_schema.columns WHERE table_name='servers';字符集不一致是乱码根因——库是 utf8mb4,表是 latin1,或连接客户端用的字符集和库不一致。
连接字符集:
sql
SHOW VARIABLES LIKE 'character_set%';character_set_client、character_set_connection、character_set_results 这几个要一致,通常都是 utf8mb4。连接时指定:
bash
mysql --default-character-set=utf8mb4 -uroot -p或在 my.cnf:
ini
[client]
default-character-set=utf8mb4
[mysqld]
character_set_server=utf8mb4全文 utf8mb4 统一——库、表、字段、连接,全用 utf8mb4,不要混 utf8 和 utf8mb4(第 1 篇讲过 utf8 是残缺的)。
已有乱码数据的处理
已经存了乱码的数据不好直接修。要先确认数据是怎么存进去的(什么字符集写入、什么字符集读出),再用 CONVERT 转换。乱码数据往往是"写入时字符集不对",转换要对症。预防胜于治疗——新库一开始就统一 utf8mb4。
六、现场保存
出大故障时,在动手修之前先保存现场——日志、进程状态、连接列表。修的过程中状态会变,没保存就回溯不了:
bash
# 保存错误日志
cp /data/mysql/logs/error.log /tmp/error-$(date +%F-%H%M%S).log
# 保存进程列表
mysql -uroot -p -e "SHOW FULL PROCESSLIST" > /tmp/processlist-$(date +%F-%H%M%S).txt
# 保存复制状态
mysql -uroot -p -e "SHOW REPLICA STATUS\G" > /tmp/replica-$(date +%F-%H%M%S).txt出了事故要复盘时,这些现场数据是依据。先存再修,别等修完发现要查原因时啥都没了。
排查的共同思路
不管哪种故障:
- 先看错误日志——它比任何猜测都准
- 分清故障类型——启动、连接、磁盘、字符集,排查方向不同
- 保存现场再动手——便于复盘
- 查配置和权限——大量故障是配置写错或权限不对
- 对照正常状态——不知道正不正常时,和一台正常的 MySQL 对比
系列收尾
MySQL 系列 15 篇走完了。从装一个 MySQL 开始,到 SQL、索引、InnoDB、事务、性能、账号、备份、复制、高可用、故障排查。这套覆盖了一个 MySQL 运维该掌握的核心。
记住一条主线:MySQL 出问题,先看错误日志,再分清故障类型,按类型走对应排查路径。 不靠猜,靠日志和数据。