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 为什么突然变慢?

通常从这几个方向排查:

  1. SQL 本身发生变化
  2. 数据量突然增长
  3. 索引失效
  4. 执行计划变化
  5. 锁等待
  6. CPU 打满
  7. 内存压力
  8. 磁盘 IO 高
  9. 连接数暴增
  10. 临时表和排序过多
  11. 大事务
  12. 大量并发查询

第一步通常:

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 本身出问题,而是因为人在没搞清楚问题之前,先执行了一个“看起来能解决”的危险操作。

在这里插入图片描述

posted @ 2026-08-31 10:15  JavaPub  阅读(6)  评论(0)    收藏  举报