MySQL 常用命令大全 + 常见问题排查大全

MySQL 真正难的地方,不是会不会写 SELECT。
而是服务器出问题的时候,你能不能快速判断:
- MySQL 到底有没有启动?
- 为什么连不上?
- 为什么突然变慢?
- 哪条 SQL 在拖垮数据库?
- 为什么 CPU 跑满?
- 为什么连接数爆了?
- 为什么磁盘越来越大?
- 为什么出现死锁?
- 为什么主从延迟?
- 为什么某张表突然查不动了?
这篇文章整理一份 MySQL 常用命令 + 日常运维 + 故障排查手册。
建议收藏。
一、先确认 MySQL 是否正常运行
Linux 服务器上首先执行:
systemctl status mysql
有些系统服务名是:
systemctl status mysqld
启动 MySQL:
sudo systemctl start mysql
停止:
sudo systemctl stop mysql
重启:
sudo systemctl restart mysql
设置开机启动:
sudo systemctl enable mysql
二、查看 MySQL 版本
mysql --version
进入 MySQL 后:
SELECT VERSION();
例如:
8.0.x
三、登录 MySQL
最基本:
mysql -u root -p
输入密码后登录。
指定主机:
mysql -h 127.0.0.1 -u root -p
指定端口:
mysql -h 127.0.0.1 -P 3306 -u root -p
指定数据库:
mysql -u root -p mydb
完整形式:
mysql \
-h 127.0.0.1 \
-P 3306 \
-u root \
-p \
mydb
四、退出 MySQL
exit;
或者:
quit;
快捷方式:
Ctrl + D
五、数据库常用命令
查看所有数据库
SHOW DATABASES;
创建数据库
CREATE DATABASE test;
推荐指定字符集:
CREATE DATABASE test
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
删除数据库
DROP DATABASE test;
这个操作不可逆,执行前一定确认。
进入数据库
USE test;
查看当前数据库
SELECT DATABASE();
查看创建数据库的 SQL
SHOW CREATE DATABASE test;
六、数据表常用命令
查看所有表
SHOW TABLES;
查看表结构
DESC users;
或者:
DESCRIBE users;
查看完整建表语句
SHOW CREATE TABLE users;
这个命令非常重要。
排查:
- 字段类型
- 索引
- 字符集
- 存储引擎
- 默认值
经常都会用到。
创建表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(100) NOT NULL,
email VARCHAR(255),
status TINYINT NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
);
删除表
DROP TABLE users;
谨慎操作。
清空表
TRUNCATE TABLE users;
与:
DELETE FROM users;
并不完全一样。
通常:
TRUNCATE
速度更快,并且会重新处理自增值。
修改表名
RENAME TABLE users TO user_info;
七、增删改查
这是 MySQL 最基础的 CRUD。
八、INSERT 插入数据
插入一条:
INSERT INTO users (username, email)
VALUES ('Tom', 'tom@example.com');
插入多条:
INSERT INTO users (username, email)
VALUES
('Tom', 'tom@example.com'),
('Jack', 'jack@example.com'),
('Lucy', 'lucy@example.com');
九、SELECT 查询
查询全部:
SELECT * FROM users;
指定字段:
SELECT id, username, email
FROM users;
条件查询:
SELECT *
FROM users
WHERE id = 1;
多个条件:
SELECT *
FROM users
WHERE status = 1
AND id > 100;
十、UPDATE 修改
UPDATE users
SET username = 'Tom2'
WHERE id = 1;
特别注意:
千万不要忘记:
WHERE
下面这种:
UPDATE users
SET status = 0;
会修改整张表。
线上数据库尤其危险。
十一、DELETE 删除
DELETE FROM users
WHERE id = 1;
同样一定注意:
WHERE
如果执行:
DELETE FROM users;
就是删除整张表的数据。
十二、WHERE 常见条件
等于:
WHERE id = 1
不等于:
WHERE id != 1
大于:
WHERE id > 100
范围:
WHERE id BETWEEN 100 AND 200
多个值:
WHERE status IN (1, 2, 3)
非多个值:
WHERE status NOT IN (0, 9)
NULL:
WHERE email IS NULL
不是 NULL:
WHERE email IS NOT NULL
十三、LIKE 模糊搜索
包含:
SELECT *
FROM users
WHERE username LIKE '%Tom%';
以 Tom 开头:
WHERE username LIKE 'Tom%'
以 Tom 结尾:
WHERE username LIKE '%Tom'
注意:
LIKE '%xxx'
很多情况下无法有效使用普通 B-Tree 索引。
数据量大时要特别注意。
十四、排序 ORDER BY
升序:
SELECT *
FROM users
ORDER BY id ASC;
降序:
SELECT *
FROM users
ORDER BY id DESC;
多个字段:
SELECT *
FROM users
ORDER BY status ASC, id DESC;
十五、LIMIT 分页
查询前 10 条:
SELECT *
FROM users
LIMIT 10;
从第 11 条开始查 10 条:
SELECT *
FROM users
LIMIT 10, 10;
或者:
SELECT *
FROM users
LIMIT 10 OFFSET 10;
十六、大分页问题
例如:
SELECT *
FROM users
ORDER BY id
LIMIT 1000000, 20;
数据量很大时可能非常慢。
更好的做法:
SELECT *
FROM users
WHERE id > 1000000
ORDER BY id
LIMIT 20;
这类方式通常叫:
基于游标 / ID 的分页
十七、COUNT
统计数量:
SELECT COUNT(*)
FROM users;
带条件:
SELECT COUNT(*)
FROM users
WHERE status = 1;
十八、GROUP BY
统计不同状态:
SELECT status, COUNT(*)
FROM users
GROUP BY status;
例如:
status count
0 100
1 5000
2 200
十九、HAVING
对聚合结果过滤:
SELECT status, COUNT(*) AS count
FROM users
GROUP BY status
HAVING count > 100;
二十、JOIN
INNER JOIN
SELECT
users.id,
users.username,
orders.id AS order_id
FROM users
INNER JOIN orders
ON users.id = orders.user_id;
LEFT JOIN
SELECT
users.id,
users.username,
orders.id AS order_id
FROM users
LEFT JOIN orders
ON users.id = orders.user_id;
实际开发中:
LEFT JOIN
非常常见。
二十一、查看表索引
SHOW INDEX FROM users;
或者:
SHOW INDEXES FROM users;
二十二、创建索引
普通索引:
CREATE INDEX idx_username
ON users(username);
联合索引:
CREATE INDEX idx_status_created
ON users(status, created_at);
唯一索引:
CREATE UNIQUE INDEX uk_email
ON users(email);
二十三、删除索引
DROP INDEX idx_username
ON users;
二十四、联合索引最左匹配
假设索引:
INDEX idx_user_status (user_id, status, created_at)
通常:
WHERE user_id = 1
可以使用。
WHERE user_id = 1
AND status = 1
也可以很好地利用索引。
但是:
WHERE status = 1
通常无法直接有效利用这个联合索引的最左列设计。
所以设计索引时一定要考虑:
查询条件顺序和实际访问模式
二十五、EXPLAIN:SQL 性能排查核心命令
遇到慢 SQL,第一反应通常应该是:
EXPLAIN
SELECT *
FROM users
WHERE email = 'test@example.com';
例如:
EXPLAIN SELECT * FROM users WHERE id = 100;
重点关注:
type
possible_keys
key
rows
Extra
二十六、EXPLAIN 中 type 怎么看
一般来说,从比较好到比较差,大致可以理解为:
system
const
eq_ref
ref
range
index
ALL
如果看到:
ALL
通常代表:
全表扫描
这时候就需要重点关注。
但不是所有 ALL 都一定有问题。
例如一张只有几十条数据的小表,全表扫描可能完全正常。
二十七、重点看 key
key
表示 MySQL 实际选择了哪个索引。
如果:
key = NULL
说明没有使用索引。
二十八、重点看 rows
例如:
rows = 1000000
意味着优化器预计需要扫描大量数据。
通常需要检查:
- WHERE 条件
- 索引
- JOIN
- 排序
- 分页
二十九、EXPLAIN ANALYZE
新版本 MySQL 可以使用:
EXPLAIN ANALYZE
SELECT *
FROM users
WHERE status = 1;
与普通 EXPLAIN 不同,它会真正执行查询,并返回实际执行信息。
线上使用时需要注意:
它真的可能执行 SQL。
不要对有副作用或成本很高的操作随便使用。
三十、查看当前连接
SHOW PROCESSLIST;
查看完整 SQL:
SHOW FULL PROCESSLIST;
这也是线上排障最重要的命令之一。
三十一、Processlist 常见状态
你可能会看到:
Sleep
Query
Locked
Sending data
Creating sort index
Waiting for table metadata lock
其中有些值得重点关注。
三十二、大量 Sleep
例如:
Sleep
Sleep
Sleep
Sleep
非常多。
可能原因:
- 应用连接池设置过大
- 连接没有及时释放
- wait_timeout 太长
- 应用连接泄漏
查看:
SHOW VARIABLES LIKE 'wait_timeout';
三十三、查看当前连接数
SHOW STATUS LIKE 'Threads_connected';
查看最大连接数:
SHOW VARIABLES LIKE 'max_connections';
例如:
Threads_connected = 490
max_connections = 500
这就非常危险了。
三十四、连接数满了
典型错误:
Too many connections
先看:
SHOW STATUS LIKE 'Threads_connected';
然后:
SHOW FULL PROCESSLIST;
检查是不是大量:
Sleep
临时提高:
SET GLOBAL max_connections = 1000;
但是注意:
提高 max_connections 不一定是真正解决问题。
如果根因是:
应用连接泄漏
那么从 500 提到 1000,只是晚一点再爆。
真正应该检查:
- 应用连接池
- 最大连接数
- 最小空闲连接
- 连接释放
- SQL 执行时间
- wait_timeout
- 突发流量
三十五、杀掉某个 MySQL 连接
先:
SHOW FULL PROCESSLIST;
得到 ID,例如:
12345
结束:
KILL 12345;
也可以:
KILL CONNECTION 12345;
只终止当前 SQL:
KILL QUERY 12345;
线上使用一定谨慎。
三十六、查看 MySQL 全局状态
SHOW GLOBAL STATUS;
通常我们不会直接看全部。
而是筛选。
例如:
SHOW GLOBAL STATUS LIKE 'Threads_connected';
三十七、查看变量
SHOW VARIABLES;
例如查看连接数:
SHOW VARIABLES LIKE 'max_connections';
查看字符集:
SHOW VARIABLES LIKE 'character_set%';
查看超时:
SHOW VARIABLES LIKE '%timeout%';
三十八、MySQL CPU 突然 100% 怎么查?
这是非常典型的问题。
第一步:
top
或者:
htop
确认:
mysqld
确实占用大量 CPU。
然后进入 MySQL:
SHOW FULL PROCESSLIST;
重点找:
- 长时间运行的 SQL
- 大量相同 SQL
- Sending data
- Creating sort index
- Copying to tmp table
- Locked
再拿慢 SQL:
EXPLAIN
SELECT ...
检查:
- 是否没索引
- 是否索引失效
- 是否全表扫描
- 是否排序过大
- 是否 GROUP BY
- 是否 JOIN 大表
- 是否大分页
三十九、快速找到正在执行的 SQL
SHOW FULL PROCESSLIST;
如果输出很多,可以从系统表查询:
SELECT *
FROM information_schema.PROCESSLIST
WHERE COMMAND != 'Sleep'
ORDER BY TIME DESC;
四十、查询执行时间最长的连接
SELECT
ID,
USER,
HOST,
DB,
COMMAND,
TIME,
STATE,
INFO
FROM information_schema.PROCESSLIST
WHERE COMMAND != 'Sleep'
ORDER BY TIME DESC
LIMIT 20;
这是非常实用的一条排障 SQL。
四十一、慢查询日志
查看是否开启:
SHOW VARIABLES LIKE 'slow_query_log';
查看慢查询日志路径:
SHOW VARIABLES LIKE 'slow_query_log_file';
查看慢查询阈值:
SHOW VARIABLES LIKE 'long_query_time';
例如:
long_query_time = 10
表示 SQL 超过 10 秒会被记录。
四十二、临时开启慢查询
SET GLOBAL slow_query_log = 'ON';
设置 2 秒:
SET GLOBAL long_query_time = 2;
注意:
这种方式可能只在当前运行周期有效。
永久设置应该修改 MySQL 配置文件。
四十三、常见配置文件位置
Ubuntu / Debian 常见:
/etc/mysql/my.cnf
或者:
/etc/mysql/mysql.conf.d/mysqld.cnf
CentOS / Rocky Linux 常见:
/etc/my.cnf
找到 MySQL 配置:
mysql --help | grep my.cnf
四十四、MySQL 错误日志
首先可以看:
journalctl -u mysql
或者:
journalctl -u mysqld
实时查看:
journalctl -u mysql -f
常见日志文件:
/var/log/mysql/error.log
查看:
tail -f /var/log/mysql/error.log
四十五、MySQL 启动失败怎么排查?
按照这个顺序:
systemctl status mysql
然后:
journalctl -u mysql -n 200
再看:
tail -n 200 /var/log/mysql/error.log
常见原因:
- 配置文件错误
- 端口被占用
- 磁盘满
- 权限错误
- 数据目录异常
- InnoDB 启动失败
- 内存不足
- 参数配置错误
四十六、检查 3306 端口
ss -lntp | grep 3306
或者:
lsof -i :3306
如果没有监听:
说明 MySQL 可能根本没有成功启动。
四十七、MySQL 本地能连,远程连不上
这个问题非常常见。
首先检查 MySQL 监听:
ss -lntp | grep 3306
可能看到:
127.0.0.1:3306
这意味着只监听本机。
检查:
SHOW VARIABLES LIKE 'bind_address';
或者配置:
bind-address = 127.0.0.1
如果需要远程访问,可能需要调整监听地址。
但同时必须考虑安全问题。
不要简单把 3306 裸露到整个公网。
更推荐:
- 内网访问
- VPN
- SSH Tunnel
- 安全组限制来源 IP
四十八、Access denied
典型报错:
Access denied for user 'root'@'xxx'
重点检查:
SELECT user, host
FROM mysql.user;
MySQL 用户不是简单的:
root
而是类似:
'root'@'localhost'
和:
'root'@'%'
是不同的账户匹配。
四十九、创建用户
CREATE USER 'app'@'localhost'
IDENTIFIED BY 'your_password';
远程用户:
CREATE USER 'app'@'%'
IDENTIFIED BY 'your_password';
但是线上环境不建议无脑使用:
%
最好限制具体来源。
例如:
CREATE USER 'app'@'10.0.0.%'
IDENTIFIED BY 'your_password';
五十、授权
数据库全部权限:
GRANT ALL PRIVILEGES
ON mydb.*
TO 'app'@'localhost';
只读:
GRANT SELECT
ON mydb.*
TO 'reader'@'localhost';
应用通常根据实际需求授权:
GRANT SELECT, INSERT, UPDATE, DELETE
ON mydb.*
TO 'app'@'localhost';
五十一、查看用户权限
SHOW GRANTS FOR 'app'@'localhost';
五十二、删除用户
DROP USER 'app'@'localhost';
五十三、修改密码
ALTER USER 'app'@'localhost'
IDENTIFIED BY 'new_password';
五十四、字符集乱码怎么查?
查看数据库:
SHOW CREATE DATABASE mydb;
查看表:
SHOW CREATE TABLE users;
查看 MySQL 字符集:
SHOW VARIABLES LIKE 'character_set%';
查看排序规则:
SHOW VARIABLES LIKE 'collation%';
现在绝大多数业务建议优先使用:
utf8mb4
而不是:
utf8
因为 MySQL 历史上的 utf8 并不是真正完整的 UTF-8。
五十五、修改数据库字符集
ALTER DATABASE mydb
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
五十六、修改表字符集
ALTER TABLE users
CONVERT TO CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
大表执行这种操作可能非常耗时。
线上一定谨慎。
五十七、查看表大小
这个排查磁盘问题非常常用。
SELECT
table_schema AS database_name,
table_name,
ROUND(data_length / 1024 / 1024, 2) AS data_mb,
ROUND(index_length / 1024 / 1024, 2) AS index_mb,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_mb
FROM information_schema.tables
ORDER BY data_length + index_length DESC
LIMIT 20;
这样可以快速找到最大的表。
五十八、查看某个数据库大小
SELECT
table_schema,
ROUND(
SUM(data_length + index_length) / 1024 / 1024,
2
) AS size_mb
FROM information_schema.tables
WHERE table_schema = 'mydb'
GROUP BY table_schema;
五十九、查看所有数据库大小
SELECT
table_schema,
ROUND(
SUM(data_length + index_length) / 1024 / 1024,
2
) AS size_mb
FROM information_schema.tables
GROUP BY table_schema
ORDER BY size_mb DESC;
六十、MySQL 磁盘爆满怎么排查?
首先 Linux:
df -h
查看 MySQL 数据目录:
SHOW VARIABLES LIKE 'datadir';
例如:
/var/lib/mysql/
然后:
du -sh /var/lib/mysql/*
检查:
- 哪个数据库大
- 哪张表大
- binlog 是否太多
- slow log 是否太大
- error log 是否太大
- 临时文件是否异常
六十一、Binlog 占满磁盘
查看:
SHOW BINARY LOGS;
查看当前 binlog:
SHOW MASTER STATUS;
在不同版本中,复制相关命令名称可能有所调整,但核心思路一致。
查看配置:
SHOW VARIABLES LIKE 'log_bin';
查看过期策略:
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
不要直接去:
rm /var/lib/mysql/mysql-bin.*
这样非常危险。
应该优先通过 MySQL 自身管理 binlog。
六十二、删除旧 Binlog
例如:
PURGE BINARY LOGS
BEFORE '2026-08-01 00:00:00';
或者指定文件:
PURGE BINARY LOGS
TO 'mysql-bin.001000';
注意:
如果存在主从复制,一定先确认从库是否已经消费对应日志。
否则可能直接把复制搞坏。
六十三、事务常用命令
开始事务:
START TRANSACTION;
或者:
BEGIN;
提交:
COMMIT;
回滚:
ROLLBACK;
六十四、关闭自动提交
查看:
SELECT @@autocommit;
关闭:
SET autocommit = 0;
打开:
SET autocommit = 1;
六十五、为什么事务一直不提交很危险?
长事务可能导致:
- Undo 日志越来越大
- 锁长期不释放
- MVCC 历史版本堆积
- 数据清理困难
- 主从延迟
- 性能下降
所以线上应该重点避免:
长事务
六十六、查看 InnoDB 状态
排查死锁、锁等待非常重要:
SHOW ENGINE INNODB STATUS\G
注意最后:
\G
可以把结果竖向显示,更容易阅读。
重点搜索:
LATEST DETECTED DEADLOCK
六十七、死锁是什么?
例如两个事务:
事务 A:
先锁 user 1
再锁 user 2
事务 B:
先锁 user 2
再锁 user 1
双方互相等待。
就可能发生:
Deadlock
解决思路通常包括:
- 保持一致的加锁顺序
- 减少事务范围
- 缩短事务时间
- 建立正确索引
- 减少一次事务修改的数据量
- 增加应用层重试
六十八、查看当前锁等待
可以通过 Performance Schema 查询。
例如:
SELECT *
FROM performance_schema.data_lock_waits;
查看锁:
SELECT *
FROM performance_schema.data_locks;
如果数据库版本不同,具体系统表支持情况可能有所差异。
六十九、Metadata Lock 问题
你可能会在:
SHOW FULL PROCESSLIST;
看到:
Waiting for table metadata lock
非常典型。
例如有人执行:
ALTER TABLE users ...
但是另外一个长事务一直持有相关表的元数据锁。
结果 ALTER 一直等。
这时候需要检查:
SHOW FULL PROCESSLIST;
找到长时间未完成的事务或连接。
七十、查询当前事务
SELECT *
FROM information_schema.innodb_trx;
重点关注:
trx_started
trx_state
trx_mysql_thread_id
如果发现一个事务持续:
几分钟
几十分钟
甚至几个小时
通常需要重点检查。
七十一、查看长事务
SELECT
trx_id,
trx_state,
trx_started,
trx_mysql_thread_id,
trx_query
FROM information_schema.innodb_trx
ORDER BY trx_started;
七十二、SQL 为什么突然变慢?
通常从这几个方向排查:
- SQL 本身发生变化
- 数据量突然增长
- 索引失效
- 执行计划变化
- 锁等待
- CPU 打满
- 内存压力
- 磁盘 IO 高
- 连接数暴增
- 临时表和排序过多
- 大事务
- 大量并发查询
第一步通常:
SHOW FULL PROCESSLIST;
第二步:
EXPLAIN
第三步:
检查慢查询。
七十三、哪些情况会导致索引失效?
常见情况:
1. 对索引列做函数计算
WHERE DATE(created_at) = '2026-08-31'
通常不如:
WHERE created_at >= '2026-08-31 00:00:00'
AND created_at < '2026-09-01 00:00:00'
2. 前置模糊匹配
WHERE username LIKE '%Tom'
普通 B-Tree 索引通常难以有效利用。
3. 隐式类型转换
假设手机号字段是:
VARCHAR
却写:
WHERE phone = 13800138000
更合理:
WHERE phone = '13800138000'
4. 联合索引没有合理使用最左列
5. 数据量太少
MySQL 也可能判断:
直接扫描更快
所以不使用索引。
七十四、ORDER BY 很慢怎么办?
例如:
SELECT *
FROM orders
WHERE user_id = 100
ORDER BY created_at DESC
LIMIT 20;
可以考虑联合索引:
INDEX(user_id, created_at)
这样可能同时帮助:
WHERE + ORDER BY
七十五、Using filesort 是什么意思?
执行:
EXPLAIN ...
可能看到:
Using filesort
它不一定真的表示“写磁盘文件”。
本质上代表:
MySQL 需要额外排序
并不意味着一定有问题。
但如果:
- 数据量巨大
- 排序字段没索引
- SQL 高频执行
就需要重点优化。
七十六、Using temporary
可能看到:
Using temporary
表示执行过程中需要临时表。
常见于:
- GROUP BY
- DISTINCT
- ORDER BY
- UNION
也不是看到就一定代表严重问题。
关键还是:
SQL 是否真的慢
七十七、查看临时表情况
SHOW GLOBAL STATUS LIKE 'Created_tmp%';
常见:
Created_tmp_tables
Created_tmp_disk_tables
如果大量临时表落到磁盘,需要进一步分析。
七十八、查看 Buffer Pool
MySQL InnoDB 很重要的参数:
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
它决定 InnoDB 缓冲池大小。
对于专用数据库服务器来说,通常会分配较大比例的内存给 Buffer Pool。
但具体数值不能机械照抄,必须根据:
- 服务器内存
- 是否还有其他程序
- 数据规模
- 并发量
综合判断。
七十九、MySQL 内存占用很高正常吗?
不一定异常。
MySQL 本身会利用大量内存做缓存。
重点不要只看:
used memory
而应该同时关注:
- 是否持续 OOM
- 是否发生 Swap
- mysqld 是否被杀
- 内存是否持续增长
- 连接数是否过高
- per-thread buffer 是否设置过大
八十、查看 Swap
Linux:
free -h
如果 MySQL 服务器出现大量 Swap:
Swap Used 很高
往往可能导致性能明显下降。
八十一、MySQL 被 OOM Killer 杀掉
如果 MySQL 莫名其妙挂了,可以执行:
dmesg | grep -i oom
或者:
journalctl -k | grep -i oom
如果看到:
Out of memory
Killed process ... mysqld
说明 MySQL 可能因为内存不足被 Linux 杀掉。
八十二、查看 MySQL 数据目录
SHOW VARIABLES LIKE 'datadir';
例如:
/var/lib/mysql/
查看大小:
du -sh /var/lib/mysql
八十三、备份数据库 mysqldump
备份数据库:
mysqldump -u root -p mydb > mydb.sql
八十四、备份指定表
mysqldump -u root -p mydb users > users.sql
八十五、备份多个数据库
mysqldump -u root -p \
--databases db1 db2 \
> backup.sql
八十六、备份所有数据库
mysqldump -u root -p \
--all-databases \
> all.sql
八十七、恢复数据库
mysql -u root -p mydb < mydb.sql
八十八、大库备份建议
对于 InnoDB,可以考虑:
mysqldump \
--single-transaction \
-u root \
-p \
mydb > mydb.sql
这样通常可以减少对线上业务的影响。
八十九、导出查询结果
例如:
mysql -u root -p \
-e "SELECT id,username FROM mydb.users;" \
> users.txt
九十、查看当前数据库连接线程
SHOW STATUS LIKE 'Threads%';
重点:
Threads_connected
Threads_running
Threads_created
如果:
Threads_created
增长特别快,可能说明连接复用情况不好。
九十一、查看 QPS
可以看:
SHOW GLOBAL STATUS LIKE 'Queries';
然后间隔一段时间再次执行。
例如:
第二次 Queries - 第一次 Queries
-------------------------------
秒数
大致可以得到 QPS。
九十二、查看数据库运行时间
SHOW GLOBAL STATUS LIKE 'Uptime';
九十三、MySQL 服务器 load 很高怎么判断?
Linux:
uptime
然后:
top
再看:
vmstat 1
如果安装了 sysstat:
iostat -x 1
重点判断到底是:
CPU 问题
还是:
磁盘 IO 问题
如果 CPU 不高,但是:
iowait
非常高,那就可能是磁盘瓶颈。
九十四、数据库突然大量超时
排查顺序:
应用
↓
网络
↓
连接数
↓
MySQL 当前 SQL
↓
锁
↓
CPU
↓
内存
↓
磁盘 IO
先执行:
SHOW FULL PROCESSLIST;
再执行:
SHOW STATUS LIKE 'Threads_connected';
再看 Linux:
top
free -h
df -h
iostat -x 1
九十五、Can't connect to MySQL server
例如:
Can't connect to MySQL server on 'xxx'
检查:
1. 服务
systemctl status mysql
2. 端口
ss -lntp | grep 3306
3. 本机测试
mysql -h 127.0.0.1 -u root -p
4. 网络
ping 数据库IP
5. 端口连接
如果安装了 nc:
nc -vz 数据库IP 3306
6. 防火墙 / 云安全组
检查:
- 腾讯云安全组
- 阿里云安全组
- AWS Security Group
- UFW
- firewalld
九十六、查看防火墙
Ubuntu:
sudo ufw status
CentOS / Rocky Linux:
sudo firewall-cmd --list-all
不要为了图方便直接向全公网开放 3306。
九十七、Lost connection to MySQL server
常见报错:
Lost connection to MySQL server during query
可能原因:
- SQL 执行太久
- 网络中断
- MySQL 重启
- 数据包太大
- 连接超时
- OOM
- 代理超时
可以看:
SHOW VARIABLES LIKE 'max_allowed_packet';
和:
SHOW VARIABLES LIKE '%timeout%';
同时检查:
journalctl -u mysql
九十八、Packet too large
典型:
Packet too large
查看:
SHOW VARIABLES LIKE 'max_allowed_packet';
比如上传:
- 大 JSON
- 大图片
- 大 Blob
- 超大批量 INSERT
可能触发。
一般数据库并不推荐直接塞大量超大二进制文件。
九十九、Too many connections
核心排查:
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';
SHOW FULL PROCESSLIST;
然后检查应用连接池。
一百、Lock wait timeout exceeded
典型错误:
Lock wait timeout exceeded;
try restarting transaction
说明当前事务一直拿不到锁。
先查:
SHOW ENGINE INNODB STATUS\G
然后:
SELECT *
FROM information_schema.innodb_trx;
再检查锁等待。
千万不要第一反应就是把:
innodb_lock_wait_timeout
调得特别大。
那可能只是让请求等得更久。
一百零一、Deadlock found
报错:
Deadlock found when trying to get lock
排查:
SHOW ENGINE INNODB STATUS\G
找到:
LATEST DETECTED DEADLOCK
分析:
- 哪两个事务
- 操作了哪些表
- 哪些索引
- 加锁顺序是什么
最终通常还是:
优化事务和 SQL
而不是简单改一个参数。
一百零二、查询很慢,但是 EXPLAIN 有索引
这也很常见。
有索引 ≠ 一定快。
还要看:
- 返回多少行
- 扫描多少行
- 索引选择性
- 是否回表
- 是否排序
- 是否临时表
- 是否锁等待
- 是否并发过高
- 数据是否都不在缓存中
一百零三、索引太多也不是好事
每增加一个索引:
查询可能更快。
但:
INSERT
UPDATE
DELETE
成本也会增加。
因为每次写数据都需要维护索引。
索引还会占:
磁盘 + Buffer Pool
所以不要看到慢 SQL 就无脑加索引。
一百零四、查看没有主键的表
可以通过 information_schema 排查。
例如:
SELECT
t.TABLE_SCHEMA,
t.TABLE_NAME
FROM information_schema.TABLES t
LEFT JOIN information_schema.TABLE_CONSTRAINTS tc
ON t.TABLE_SCHEMA = tc.TABLE_SCHEMA
AND t.TABLE_NAME = tc.TABLE_NAME
AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
WHERE
t.TABLE_SCHEMA NOT IN (
'mysql',
'information_schema',
'performance_schema',
'sys'
)
AND tc.CONSTRAINT_NAME IS NULL;
业务表通常建议设计合适的主键。
一百零五、查看没有索引的大表
思路是结合:
information_schema.tables
和:
statistics
检查。
不过是否需要索引,最终还是应该根据:
实际 SQL
决定。
而不是根据表大小机械判断。
一百零六、主从复制常见排查思路
如果用了 MySQL Replication,核心需要关注:
- IO 线程
- SQL 线程
- 延迟
- 错误
- binlog
- relay log
传统命令:
SHOW SLAVE STATUS\G
新版本中更推荐:
SHOW REPLICA STATUS\G
重点看:
Replica_IO_Running
Replica_SQL_Running
Seconds_Behind_Source
Last_IO_Error
Last_SQL_Error
不同版本字段名称可能有所变化。
一百零七、从库延迟
如果:
Seconds_Behind_Source
持续升高。
可能原因:
- 主库写入量太大
- 从库机器性能弱
- 大事务
- 大量 DDL
- 慢 SQL
- 网络问题
- 单线程应用日志能力不足
- 磁盘 IO 慢
一百零八、主从复制断了
首先看:
SHOW REPLICA STATUS\G
重点:
Last_IO_Error
Last_SQL_Error
不要看到错误就直接:
跳过事务
因为可能造成:
主从数据不一致
应该先确定根本原因。
一百零九、数据库备份不是执行 mysqldump 就结束了
真正的备份应该考虑:
能不能恢复
而不是:
有没有 .sql 文件
至少应该定期做:
备份恢复演练
否则出了问题才发现备份损坏,就已经晚了。
一百一十、删除数据后磁盘为什么没有立刻变小?
对于 InnoDB:
DELETE FROM users ...
删除数据之后,表文件通常不会立刻缩小。
空间可能变成:
表内部可复用空间
所以你可能发现:
删除了 50GB 数据
但是:
df -h
看起来没释放。
这是很常见的。
一百一十一、OPTIMIZE TABLE
有时可以:
OPTIMIZE TABLE users;
重新组织表。
但是大表执行可能:
- 非常耗时
- 占额外磁盘
- 影响性能
- 涉及锁
线上大表不要随便执行。
一百一十二、ALTER TABLE 为什么这么危险?
例如:
ALTER TABLE orders
ADD COLUMN test VARCHAR(100);
在超大表上可能:
- 执行很久
- 占用大量 IO
- 消耗额外磁盘
- 导致锁等待
- 影响线上请求
所以生产环境做 DDL 前一定评估。
一百一十三、上线前常见 SQL 检查
建议检查:
1. 有没有 UPDATE 没 WHERE
2. 有没有 DELETE 没 WHERE
3. 有没有全表扫描
4. 有没有大分页
5. 有没有大事务
6. 有没有一次修改几百万行
7. 有没有大表 ALTER
8. 有没有新建重复索引
9. 有没有 SELECT *
10. 有没有字段类型不匹配
一百一十四、不要轻易执行的 MySQL 操作
线上尤其需要谨慎:
DROP DATABASE
DROP TABLE
TRUNCATE TABLE
DELETE FROM table;
UPDATE table SET ...;
以及大表:
ALTER TABLE
执行前至少确认:
当前环境
当前数据库
当前表
影响行数
是否有备份
一百一十五、执行 UPDATE 前的好习惯
不要直接:
UPDATE users
SET status = 0
WHERE created_at < '2025-01-01';
先执行:
SELECT COUNT(*)
FROM users
WHERE created_at < '2025-01-01';
再随机查看:
SELECT *
FROM users
WHERE created_at < '2025-01-01'
LIMIT 20;
确认数据没问题以后,再 UPDATE。
一百一十六、执行 DELETE 前的好习惯
同理:
先:
SELECT COUNT(*)
FROM users
WHERE status = 0;
然后:
SELECT *
FROM users
WHERE status = 0
LIMIT 20;
最后再考虑:
DELETE
一百一十七、大批量删除不要一次干完
不要:
DELETE FROM logs
WHERE created_at < '2025-01-01';
一次删除几千万条。
可以考虑分批:
DELETE FROM logs
WHERE created_at < '2025-01-01'
LIMIT 10000;
循环执行。
这样可以减少:
- 大事务
- 锁
- Undo 压力
- 主从延迟
一百一十八、MySQL 常用命令速查表
| 场景 | 命令 |
|---|---|
| 登录 | mysql -u root -p |
| 查看数据库 | SHOW DATABASES; |
| 进入数据库 | USE db; |
| 查看表 | SHOW TABLES; |
| 查看结构 | DESC table; |
| 查看建表 SQL | SHOW CREATE TABLE table; |
| 查看索引 | SHOW INDEX FROM table; |
| 查看连接 | SHOW FULL PROCESSLIST; |
| 查看事务 | SELECT * FROM information_schema.innodb_trx; |
| 查看 InnoDB | SHOW ENGINE INNODB STATUS\G |
| 查看慢查询 | SHOW VARIABLES LIKE 'slow_query_log%'; |
| SQL 分析 | EXPLAIN SELECT ...; |
| 实际执行分析 | EXPLAIN ANALYZE SELECT ...; |
| 当前连接数 | SHOW STATUS LIKE 'Threads_connected'; |
| 最大连接数 | SHOW VARIABLES LIKE 'max_connections'; |
| 数据目录 | SHOW VARIABLES LIKE 'datadir'; |
| 字符集 | SHOW VARIABLES LIKE 'character_set%'; |
| Buffer Pool | SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; |
| Binlog | SHOW BINARY LOGS; |
| 备份 | mysqldump |
| 恢复 | mysql db < backup.sql |
一百一十九、MySQL 出问题时,最值得先执行的 10 条命令
如果让我只保留一套线上 MySQL 故障排查命令,我会留下面这些。
1. MySQL 是否运行
systemctl status mysql
2. 看错误日志
journalctl -u mysql -n 200
3. 看 CPU
top
4. 看内存
free -h
5. 看磁盘
df -h
6. 看端口
ss -lntp | grep 3306
7. 看连接
SHOW FULL PROCESSLIST;
8. 看连接数量
SHOW STATUS LIKE 'Threads_connected';
9. 看事务和锁
SHOW ENGINE INNODB STATUS\G
10. 分析慢 SQL
EXPLAIN
SELECT ...;
一百二十、MySQL 故障排查完整思路
以后遇到 MySQL 问题,不要一上来就改参数。
建议按照下面这套顺序。
第一层:MySQL 活着吗?
↓
systemctl status mysql
第二层:日志报什么?
↓
journalctl
error.log
第三层:机器资源正常吗?
↓
CPU
内存
磁盘
IO
第四层:连接正常吗?
↓
Threads_connected
max_connections
第五层:正在执行什么?
↓
SHOW FULL PROCESSLIST
第六层:有没有慢 SQL?
↓
Slow Query Log
EXPLAIN
第七层:有没有锁?
↓
InnoDB Status
innodb_trx
data_locks
第八层:是不是数据规模问题?
↓
大表
大索引
大事务
大分页
第九层:是不是配置问题?
↓
Buffer Pool
连接数
Timeout
Binlog
第十层:是不是应用问题?
↓
连接池
SQL
事务
并发
重试
这套方法比看到报错以后直接搜索:
“把某个参数调大”
要靠谱得多。
总结
MySQL 运维真正重要的并不是背几百个参数。
真正需要掌握的是一套固定的排查逻辑:
先看服务
↓
再看日志
↓
再看资源
↓
再看连接
↓
再看 SQL
↓
再看锁和事务
↓
最后再考虑参数配置
对于日常开发来说,优先掌握下面几个核心能力:
SHOW FULL PROCESSLIST
EXPLAIN
SHOW ENGINE INNODB STATUS
information_schema
performance_schema
slow query log
mysqldump
基本已经可以解决相当一部分 MySQL 线上问题。
最后记住一个非常重要的原则:
线上数据库遇到问题时,先查清楚发生了什么,再决定改什么。
很多数据库事故,不是因为 MySQL 本身出问题,而是因为人在没搞清楚问题之前,先执行了一个“看起来能解决”的危险操作。


浙公网安备 33010602011771号