MySQL 常用运维指令手册
MySQL 常用运维指令手册
适用版本:MySQL 5.7 / 8.0 / 8.4 LTS / 9.7 LTS / 26.x Innovation 约定:
#root 或 sudo,$普通用户,mysql>SQL 提示符,<xxx>为占位符。 差异标注:正文中用> **版本差异**引用块标注跨版本不一致之处,无标注表示通用。 更新时间:2026-11
目录
- 版本与支持周期
- 下载地址与安装
- 服务启停与初始化
- 客户端连接
- 配置文件与参数
- 账号、权限与安全
- 库表日常操作
- 备份与恢复
- binlog 与主从复制
- 日志体系
- 性能诊断与优化
- 空间与容量管理
- 高可用:MGR / InnoDB Cluster
- 升级与迁移
- 高频故障速查
- 危险命令与避坑清单
- 附录:常用 SQL 与参数速查
1. 版本与支持周期
1.1 发布模型
MySQL 8.0 之后 Oracle 把版本拆成两条线:
| 轨道 | 命名 | 特点 | 适合场景 |
|---|---|---|---|
| LTS | 8.4、9.7 | 功能冻结,只做安全与 Bug 修复,季度小版本 | 生产环境,默认选择 |
| Innovation | 9.0~9.6、26.x | 新特性先落地,支持到下一个 Innovation 发布 | 预研、可快速升级的业务 |
版本差异:自 2026-07 的
26.7.0起,Innovation 轨道改用日历版本号YY.M.P(26 = 2026 年,7 = 7 月,0 = 补丁号)。所以看到26.10.0不要以为是"未来版本",它就是 2026 年 10 月版。LTS 线仍保留 8.4 / 9.7 的原有编号。
1.2 生命周期对照(2026-11 时点)
| 版本 | GA 时间 | Premier 支持至 | Extended 支持至 | 状态 |
|---|---|---|---|---|
| 5.7 | 2015-10 | 2020-10-31 | 2023-10-31 | 已 EOL,禁止新部署 |
| 8.0 | 2018-04 | 2025-04-30 | 2026-04-30 | 已 EOL,仅剩延保 |
| 8.4 LTS | 2024-04-30 | 2029-04-30 | 2032-04-30 | 活跃,推荐 |
| 9.7 LTS | 2026-04-21 | 2031-04-30 | 2034-04-30 | 活跃,新版首选 |
| 9.0 ~ 9.6 | 2024-07 ~ 2026-01 | 至下一个 Innovation | 同左 | 均已终止 |
| 26.x Innovation | 2026-07 起 | 至下一个 Innovation | 同左 | 活跃,预研用 |
三个必须记住的结论:
- 8.0 已经停止补丁(2026-04-30 走完最后一个 8.0.46)。还在跑 8.0 的实例,等于在裸奔,升级路径是
8.0 → 8.4 → 9.7,不能跨 LTS 直接跳。 - 8.4 是当前最稳的落点,生态(XtraBackup、云厂商 RDS、ORM、监控插件)适配最完整。
- 9.7 适合新项目,但升级前必须确认中间件、备份工具、驱动链已适配。
1.3 版本识别
mysql --version # mysql Ver 8.4.11 for Linux on x86_64 (MySQL Community Server - GPL)
mysqld --version # 服务端版本
mysqladmin -uroot -p version # 运行中实例的版本与 uptime
SELECT VERSION(); -- 8.4.11
SELECT @@version_comment; -- MySQL Community Server - GPL
SHOW VARIABLES LIKE 'version%';
SELECT @@version_compile_os, @@version_compile_machine;
批量盘点(多实例):
for p in 3306 3307 3308; do
mysqladmin -uroot -p"$PASS" -h127.0.0.1 -P$p version 2>/dev/null | grep -E 'Server version|Uptime'
done
2. 下载地址与安装
2.1 官方入口总表
| 用途 | 地址 |
|---|---|
| 下载总入口 | https://dev.mysql.com/downloads/ |
| Community Server(各平台主包) | https://dev.mysql.com/downloads/mysql/ |
| YUM / DNF 仓库配置包(RHEL、Oracle Linux、CentOS、Fedora) | https://dev.mysql.com/downloads/repo/yum/ |
| APT 仓库配置包(Ubuntu、Debian) | https://dev.mysql.com/downloads/repo/apt/ |
| SLES / openSUSE 仓库 | https://dev.mysql.com/downloads/repo/suse/ |
| Docker 镜像(Oracle 官方仓库) | https://container-registry.oracle.com/ → MySQL → community-server |
| MySQL Shell(含升级检查、备份工具) | https://dev.mysql.com/downloads/shell/ |
| MySQL Router | https://dev.mysql.com/downloads/router/ |
| MySQL Workbench(图形客户端) | https://dev.mysql.com/downloads/workbench/ |
| Connector/J、ODBC、Python 等驱动 | https://dev.mysql.com/downloads/connector/ |
| 历史归档版本(找老版本必用) | https://downloads.mysql.com/archives/community/ |
| 官方文档(8.4 / 9.7 / 26.x 分册) | https://dev.mysql.com/doc/ |
| 版本发布公告(确认最新小版本) | https://forums.mysql.com/ (Announcing ... Releases 帖) |
国内加速镜像(路径与可用性以镜像站当前状态为准):
# 清华 TUNA
https://mirrors.tuna.tsinghua.edu.cn/mysql/
# 阿里云
https://mirrors.aliyun.com/mysql/
提醒:镜像只同步 yum/apt 仓库和部分 tarball,不一定同步最新小版本。生产环境建议从
dev.mysql.com取包并用 MD5 + GnuPG 校验;下载页每个文件都提供 MD5 和Signature链接。
校验下载包:
md5sum mysql-8.4.11-linux-glibc2.28-x86_64.tar.xz
# 与页面 MD5 对比;GPG 校验:
gpg --keyserver pgp.mit.edu --recv-keys BCA43417C96213EE # MySQL 构建签名密钥,以页面为准
gpg --verify mysql-8.4.11-linux-glibc2.28-x86_64.tar.xz.asc mysql-8.4.11-linux-glibc2.28-x86_64.tar.xz
2.2 RHEL / CentOS / Oracle Linux:YUM/DNF 安装
仓库配置包命名规则:mysql{84|97}-community-release-{el8|el9|el10}-{版本号}.noarch.rpm。包名前缀决定默认启用的系列。
# 1) 下载并安装仓库配置包(以 EL9 + 8.4 LTS 为例)
# 当前文件名可从 https://dev.mysql.com/downloads/repo/yum/ 获取,形如:
# mysql84-community-release-el9-4.noarch.rpm
# mysql97-community-release-el9-1.noarch.rpm
dnf install -y https://dev.mysql.com/get/mysql84-community-release-el9-4.noarch.rpm
# 2) 确认仓库已生效
dnf repolist enabled | grep mysql
# mysql-8.4-lts-community MySQL 8.4 LTS Community Server
# mysql-tools-8.4-lts-community MySQL Tools 8.4 LTS Community
# 3) EL8 系必须先禁用系统自带 mysql 模块,否则会屏蔽官方包
dnf module disable mysql -y
# 4) 安装
dnf install -y mysql-community-server
# 5) 启动
systemctl enable --now mysqld
切换版本系列(同一时间只能启用一个系列):
# 查看所有子仓库
dnf repolist all | grep mysql
# 从 8.4 切到 9.7
dnf config-manager --disable mysql-8.4-lts-community
dnf config-manager --enable mysql-9.7-lts-community
# 或直接改配置文件,把目标段的 enabled 改成 1,其余改 0
vi /etc/yum.repos.d/mysql-community.repo
/etc/yum.repos.d/mysql-community.repo 典型片段(EL9,8.4):
[mysql-8.4-lts-community]
name=MySQL 8.4 LTS Community Server
baseurl=http://repo.mysql.com/yum/mysql-8.4-community/el/9/$basearch/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql-2025
避坑:一旦启用 MySQL 官方仓库,一次普通的
dnf update就可能把系统自带的mariadb-libs替换掉,进而影响依赖它的服务。上线前先dnf update --assumeno看清单。
安装组件:
dnf install -y mysql-community-client mysql-community-libs mysql-community-devel
dnf install -y mysql-shell mysql-router mysql-workbench-community
dnf --disablerepo='*' --enablerepo='mysql*-community*' list available # 看仓库里都有什么
2.3 Ubuntu / Debian:APT 安装
# 1) 下载 APT 配置包(当前版本 mysql-apt-config_0.8.40-1_all.deb,路径以下载页为准)
wget https://dev.mysql.com/get/mysql-apt-config_0.8.40-1_all.deb
# 2) 安装,弹出界面里用方向键选择 mysql-server 版本(8.4 LTS / 9.7 LTS / Innovation)
sudo dpkg -i mysql-apt-config_0.8.40-1_all.deb
# 3) 更新索引并安装
sudo apt-get update
sudo apt-get install -y mysql-server
# 4) 服务管理(Debian 系服务名就是 mysql,不是 mysqld)
sudo systemctl enable --now mysql
非交互安装(自动化脚本用):
export DEBIAN_FRONTEND=noninteractive
sudo debconf-set-selections <<'EOF'
mysql-apt-config mysql-apt-config/select-server select mysql-8.4-lts
EOF
sudo -E dpkg -i mysql-apt-config_0.8.40-1_all.deb
sudo apt-get update && sudo apt-get install -y mysql-server
改完仓库版本后需要重新跑 apt-get update,必要时 apt-get install --only-upgrade mysql-server。
避坑:APT 配置包会写入
/etc/apt/sources.list.d/mysql.list,同时导入MYSQL-GPG-KEY。如果apt update报NO_PUBKEY,重新执行dpkg-reconfigure mysql-apt-config让脚本重导密钥,不要手工--allow-unauthenticated。
2.4 通用二进制包(tar.xz)安装
适合无外网、不能装仓库、要跑多实例的场景。
# 1) 准备依赖
dnf install -y libaio ncurses-compat-libs numactl openssl
# 2) 解包到统一目录
tar -xf mysql-8.4.11-linux-glibc2.28-x86_64.tar.xz -C /usr/local
ln -s /usr/local/mysql-8.4.11-linux-glibc2.28-x86_64 /usr/local/mysql
# 3) 建用户与目录
groupadd -r mysql && useradd -r -g mysql -s /bin/false mysql
mkdir -p /data/mysql/{data,logs,tmp,binlog}
chown -R mysql:mysql /data/mysql
# 4) 配置文件
cat > /etc/my.cnf <<'EOF'
[mysqld]
user=mysql
basedir=/usr/local/mysql
datadir=/data/mysql/data
socket=/data/mysql/mysql.sock
pid-file=/data/mysql/mysqld.pid
port=3306
log-error=/data/mysql/logs/error.log
log-bin=/data/mysql/binlog/mysql-bin
server-id=1
character-set-server=utf8mb4
collation-server=utf8mb4_0900_ai_ci
innodb_buffer_pool_size=4G
innodb_redo_log_capacity=1G
max_connections=1000
EOF
# 5) 初始化(会生成临时 root 密码,写在 error log 里)
/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --initialize --user=mysql
# 6) 取临时密码
grep -i 'temporary password' /data/mysql/logs/error.log
# 7) 启动
/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf --user=mysql &
配置 systemd 托管:
# /etc/systemd/system/mysqld.service
[Unit]
Description=MySQL Server
After=network.target
[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf
ExecReload=/bin/kill -HUP $MAINPID
LimitNOFILE=65535
Restart=on-failure
RestartSec=5
PrivateTmp=true
[Install]
WantedBy=multi-user.target
systemctl daemon-reload && systemctl enable --now mysqld
版本差异:
--initialize生成随机临时密码;--initialize-insecure生成空密码 root,仅限内网一次性初始化,绝对不要在生产使用。 8.4 的二进制包还提供--initialize的--init-file方式注入初始 SQL,用于自动化改密。
2.5 Docker 部署
官方推荐 Oracle Container Registry,镜像名 container-registry.oracle.com/mysql/community-server;Docker Hub 上也有 mysql 官方镜像,两者内容同源。
# 拉取(tag 可选 8.4 / 9.7 / 26.7 / latest;latest = 最新 Innovation)
docker pull container-registry.oracle.com/mysql/community-server:8.4
# 启动(数据落盘 + 自定义配置)
docker run -d --name mysql84 \
--restart on-failure \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD='Str0ng#Pass' \
-e MYSQL_DATABASE=appdb \
-e MYSQL_USER=appuser \
-e MYSQL_PASSWORD='App#Pass' \
-v /data/mysql84/data:/var/lib/mysql \
-v /data/mysql84/conf/my.cnf:/etc/my.cnf \
container-registry.oracle.com/mysql/community-server:8.4
# 看日志与健康状态
docker ps # STATUS 从 (health: starting) 变成 (healthy) 才算可用
docker logs -f mysql84
docker logs mysql84 2>&1 | grep GENERATED # 未指定 ROOT_PASSWORD 时取随机密码
# 容器内连接
docker exec -it mysql84 mysql -uroot -p
# 进 shell 排障
docker exec -it mysql84 bash
常用环境变量:
| 变量 | 作用 |
|---|---|
MYSQL_ROOT_PASSWORD |
root 密码,必填之一 |
MYSQL_RANDOM_ROOT_PASSWORD=1 |
随机 root 密码,打印到日志 |
MYSQL_DATABASE |
初始化时建库 |
MYSQL_USER / MYSQL_PASSWORD |
建普通账号并授权该库 |
MYSQL_ONETIME_PASSWORD=1 |
首次登录强制改密(默认开启) |
MYSQL_TCP_PORT |
改监听端口 |
避坑:容器删了数据就没了,
-v挂载必须做;docker rm -v会连卷一起删。升级镜像时不要docker rm旧容器,而是用新镜像 + 旧数据目录起新容器,确认无误再删旧的。
2.6 Windows 安装
| 形式 | 文件 | 说明 |
|---|---|---|
| MSI 安装包 | mysql-<version>-winx64.msi |
带 Configurator 图形配置,推荐 |
| ZIP 免安装 | mysql-<version>-winx64.zip |
解压后手工 mysqld --initialize + 注册服务 |
# ZIP 方式初始化并注册服务(管理员 PowerShell)
mysqld --initialize --console
mysqld --install MySQL84 --defaults-file="C:\mysql\my.ini"
net start MySQL84
mysql -uroot -p
2.7 初始化后的必做四步
# 1) 用临时密码登录并立即改密
mysql -uroot -p
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStr0ng#Pass';
# 2) 跑安全向导:删匿名用户、禁 root 远程、删 test 库、重载权限
mysql_secure_installation
-- 3) 确认字符集与时区(8.0+ 默认已是 utf8mb4)
SHOW VARIABLES LIKE 'character_set_server';
SHOW VARIABLES LIKE 'collation_server';
SELECT @@system_time_zone, @@time_zone, NOW();
-- 4) 确认认证插件(8.4 默认 caching_sha2_password)
SELECT user, host, plugin FROM mysql.user;
3. 服务启停与初始化
3.1 systemd 管理
systemctl start mysqld # RHEL 系服务名 mysqld
systemctl stop mysqld
systemctl restart mysqld
systemctl reload mysqld # 重载配置(仅部分参数可动态生效)
systemctl status mysqld
systemctl enable mysqld # 开机自启
systemctl is-enabled mysqld
systemctl list-units --type=service | grep -i mysql
journalctl -u mysqld -n 200 --no-pager
journalctl -u mysqld --since "2026-11-05 09:00" --until "2026-11-05 10:00"
版本差异:Debian/Ubuntu 官方包服务名是
mysql,二进制安装习惯写mysqld。写脚本时用systemctl list-unit-files | grep -E '^(mysql|mysqld)\.service'先判断。
3.2 启动参数与配置文件优先级
mysqld --verbose --help | head -30 # 看默认读取顺序与编译默认值
mysqld --print-defaults # 打印当前生效的配置项
mysqld --validate-config # 只校验配置语法,不启动(排障神器)
mysqld --defaults-file=/etc/my.cnf --initialize --user=mysql
配置文件读取顺序(后面覆盖前面):
/etc/my.cnf → /etc/mysql/my.cnf → $MYSQL_HOME/my.cnf → ~/.my.cnf → --defaults-file 指定文件(唯一)
关键:一旦命令行给了
--defaults-file,MySQL 只读这一个文件,其他路径全部忽略。多实例部署必须给每个实例独立的 defaults-file,否则会互相抢 socket 和 pid。
3.3 多实例(同一台机器跑 3 个 MySQL)
for i in 3306 3307 3308; do
mkdir -p /data/mysql$i/{data,logs,tmp}
chown -R mysql:mysql /data/mysql$i
mysqld --defaults-file=/etc/my$i.cnf --initialize --user=mysql
done
/etc/my3307.cnf 关键差异只有四行:port、socket、datadir、pid-file。其余可共用。
3.4 优雅关闭与强制终止
mysqladmin -uroot -p shutdown # 推荐,等事务回滚完成
systemctl stop mysqld # 等价
mysqladmin -uroot -p shutdown --connect-timeout=60
# 进程无响应时(先尝试 TERM,再考虑 KILL)
kill -TERM $(cat /data/mysql/mysqld.pid)
危险:
kill -9 mysqld会跳过 InnoDB 正常 shutdown,下次启动要走崩溃恢复(redo 回放)。数据一般不会丢,但恢复时间可能很长,且未刷盘的 binlog 可能丢失。非到万不得已不要用。
4. 客户端连接
4.1 基本连接
mysql -uroot -p # 本机 socket
mysql -uroot -p -h127.0.0.1 -P3306 # TCP
mysql -uroot -p -h192.168.1.10 -P3306
mysql -uroot -p -S /data/mysql/mysql.sock # 指定 socket
mysql -uroot -p --protocol=TCP # 强制走 TCP
mysql -uroot -p -e "SELECT VERSION();" # 执行单条 SQL 后退出
mysql -uroot -p dbname < init.sql # 导入 SQL 文件
mysql -uroot -p -N -B -e "SELECT 1" # 无表头、Tab 分隔,适合脚本
常见坑:
-hlocalhost走 socket,-h127.0.0.1走 TCP。授权里'user'@'localhost'与'user'@'127.0.0.1'是两个不同账号,连不上时先确认这一点。
4.2 免密与多环境管理
# ~/.my.cnf 权限必须 600,否则 mysql 会忽略并告警
[client]
user=ops
password=Ops#2026
host=127.0.0.1
port=3306
default-character-set=utf8mb4
[mysql]
prompt="\\u@\\h [\\d]> "
chmod 600 ~/.my.cnf
mysql --print-defaults # 确认读取到的凭据
mysql --login-path=prod # 或用 mysql_config_editor 加密存储
mysql_config_editor set --login-path=prod --host=10.0.0.11 --user=ops --password
mysql --login-path=prod
mysql_config_editor print --all
4.3 连通性排查三步
# 1) 端口通不通
ss -lntp | grep 3306
telnet 10.0.0.11 3306
nc -zv 10.0.0.11 3306
# 2) 服务活不活
mysqladmin -uroot -p ping
mysqladmin -uroot -p status
# 3) 账号能不能登
mysql -uops -p -h10.0.0.11 -P3306 -e "SELECT CURRENT_USER(), USER();"
-- 服务端看到的连接来源,和客户端以为的不一定一样
SELECT USER(), CURRENT_USER(), @@hostname, @@port;
SHOW PROCESSLIST;
SELECT * FROM information_schema.processlist WHERE user='ops';
5. 配置文件与参数
5.1 参数查看
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW GLOBAL VARIABLES LIKE '%timeout%';
SHOW SESSION VARIABLES LIKE 'sql_mode';
SELECT @@global.max_connections, @@session.sql_mode;
SHOW STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool%';
5.2 参数修改的三种方式
| 方式 | 命令 | 生效范围 | 是否持久 |
|---|---|---|---|
| 运行时全局 | SET GLOBAL x=y; |
新连接 | 重启丢失 |
| 运行时持久化 | SET PERSIST x=y; |
新连接 | 写入 mysqld-auto.cnf,重启保留 |
| 只写配置不生效 | SET PERSIST_ONLY x=y; |
无 | 下次重启生效(适合只读参数) |
| 改配置文件 | vi /etc/my.cnf + 重启 |
全部 | 保留 |
SET GLOBAL max_connections = 2000;
SET PERSIST max_connections = 2000;
SET PERSIST_ONLY innodb_buffer_pool_size = 8589934592;
RESET PERSIST max_connections; -- 撤销持久化
RESET PERSIST; -- 清空全部持久化项
版本差异:
SET PERSIST从 8.0 开始提供,5.7 只能改配置文件重启。持久化内容在$DATADIR/mysqld-auto.cnf,不要手工编辑,用RESET PERSIST管理。
动态修改 buffer pool(8.0+ 支持在线扩缩,按 chunk 调整):
SELECT @@innodb_buffer_pool_size/1024/1024/1024 AS gb, @@innodb_buffer_pool_instances;
SET GLOBAL innodb_buffer_pool_size = 8589934592;
SHOW STATUS LIKE 'Innodb_buffer_pool_resize_status';
5.3 生产必调参数清单
| 参数 | 建议值 | 说明 |
|---|---|---|
innodb_buffer_pool_size |
物理内存 50%~70% | 单实例最大性能杠杆,别低于热数据量 |
innodb_buffer_pool_instances |
buffer pool ≥ 8G 时设 8 | 减少争用 |
innodb_redo_log_capacity |
2~8G | 8.0.30+ 用这一个参数替代 innodb_log_file_size |
innodb_flush_log_at_trx_commit |
1(金融级)/ 2(可容忍 1s 丢失) | 1 最安全,2 快 |
sync_binlog |
1(默认) | 与上一项共同决定崩溃安全性 |
max_connections |
按业务压测,500~3000 | 配合连接池,不要盲目调大 |
innodb_io_capacity / _max |
SSD 2000 / 4000 | 控制刷脏速度 |
binlog_expire_logs_seconds |
604800(7 天) | 默认 30 天,磁盘吃紧时调小 |
slow_query_log + long_query_time |
ON / 1 | 慢日志是排障基础,必须开 |
character_set_server |
utf8mb4 | 8.0+ 默认正确 |
transaction_isolation |
REPEATABLE-READ | 默认,除非明确需要 RC |
innodb_dedicated_server |
专用机可 ON | 自动按内存/CPU 推导 buffer pool 与 redo 大小 |
注意:
innodb_dedicated_server=ON会覆盖你手写的innodb_buffer_pool_size、innodb_redo_log_capacity等参数,调优冲突时先确认它是不是开着。
5.4 配置文件模板(8.4 LTS 生产参考)
[mysqld]
user=mysql
port=3306
basedir=/usr/local/mysql
datadir=/data/mysql/data
socket=/data/mysql/mysql.sock
pid-file=/data/mysql/mysqld.pid
tmpdir=/data/mysql/tmp
# 网络
bind-address=0.0.0.0
max_connections=2000
max_connect_errors=10000
wait_timeout=600
interactive_timeout=600
# 字符集
character-set-server=utf8mb4
collation-server=utf8mb4_0900_ai_ci
skip-character-set-client-handshake
# InnoDB
innodb_buffer_pool_size=32G
innodb_buffer_pool_instances=8
innodb_redo_log_capacity=4G
innodb_flush_log_at_trx_commit=1
innodb_flush_method=O_DIRECT
innodb_io_capacity=2000
innodb_io_capacity_max=4000
innodb_file_per_table=ON
innodb_print_all_deadlocks=ON
# 日志
log-error=/data/mysql/logs/error.log
slow_query_log=ON
slow_query_log_file=/data/mysql/logs/slow.log
long_query_time=1
log_queries_not_using_indexes=OFF
log_bin=/data/mysql/binlog/mysql-bin
binlog_format=ROW
binlog_expire_logs_seconds=604800
max_binlog_size=1G
sync_binlog=1
# 复制
server-id=1
gtid_mode=ON
enforce_gtid_consistency=ON
binlog_row_image=FULL
# 时区
default-time-zone='+08:00'
[client]
socket=/data/mysql/mysql.sock
default-character-set=utf8mb4
6. 账号、权限与安全
6.1 账号管理
-- 建账号(8.0+ 默认 caching_sha2_password)
CREATE USER 'app'@'10.0.0.%' IDENTIFIED BY 'App#Str0ng2026';
-- 指定认证插件
CREATE USER 'legacy'@'10.0.0.%' IDENTIFIED WITH caching_sha2_password BY 'Legacy#2026';
-- 要求 SSL
CREATE USER 'sec'@'%' IDENTIFIED BY 'Sec#2026' REQUIRE SSL;
-- 改密码
ALTER USER 'app'@'10.0.0.%' IDENTIFIED BY 'New#Pass2026';
ALTER USER 'app'@'10.0.0.%' IDENTIFIED BY 'New#Pass2026' RETAIN CURRENT PASSWORD;
-- 锁账号 / 解锁
ALTER USER 'app'@'10.0.0.%' ACCOUNT LOCK;
ALTER USER 'app'@'10.0.0.%' ACCOUNT UNLOCK;
-- 强制下次登录改密(8.0.14+)
ALTER USER 'app'@'10.0.0.%' PASSWORD EXPIRE;
-- 有效期策略
ALTER USER 'app'@'10.0.0.%' PASSWORD EXPIRE INTERVAL 90 DAY;
ALTER USER 'app'@'10.0.0.%' PASSWORD EXPIRE NEVER;
-- 删除
DROP USER 'app'@'10.0.0.%';
-- 改用户名/主机
RENAME USER 'app'@'10.0.0.%' TO 'app'@'10.0.1.%';
版本差异:8.4 起
mysql_native_password插件默认禁用,老客户端/老 ORM 若报Authentication plugin 'mysql_native_password' cannot be loaded,要么升级客户端,要么在服务端显式开启:mysqld --mysql-native-password=ON(my.cnf 中写mysql-native-password=ON)。9.0 起该插件已彻底移除,只能用caching_sha2_password,此时只能升级客户端驱动。 另外 8.4 移除了--default-authentication-plugin,改由--authentication-policy控制默认插件。
6.2 权限授予
-- 库级读写
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'app'@'10.0.0.%';
-- 只读账号
GRANT SELECT, SHOW VIEW ON appdb.* TO 'ro'@'%';
-- 单表
GRANT SELECT ON appdb.orders TO 'report'@'%';
-- 管理类权限
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'monitor'@'%';
GRANT RELOAD, PROCESS, REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'backup'@'%';
-- 全部权限(慎用,别给业务账号)
GRANT ALL PRIVILEGES ON appdb.* TO 'dba'@'10.0.0.%';
-- 只给列
GRANT SELECT (id, name) ON appdb.users TO 'api'@'%';
-- 收回
REVOKE DELETE ON appdb.* FROM 'app'@'10.0.0.%';
-- 查看
SHOW GRANTS FOR 'app'@'10.0.0.%';
SHOW GRANTS FOR CURRENT_USER();
FLUSH PRIVILEGES; -- 仅当直接改 mysql 库授权表后才需要
关键:8.0 起
GRANT不能隐式建用户,必须先CREATE USER。5.7 的GRANT ... IDENTIFIED BY写法已失效。FLUSH PRIVILEGES在正常GRANT/REVOKE后是不需要的,它只用于人为修改mysql.user等表之后的刷新。
6.3 角色(8.0+)
CREATE ROLE 'role_ro', 'role_rw';
GRANT SELECT ON appdb.* TO 'role_ro';
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'role_rw';
GRANT 'role_rw' TO 'app'@'10.0.0.%';
SET DEFAULT ROLE 'role_rw' TO 'app'@'10.0.0.%';
-- 会话内启用
SET ROLE 'role_rw';
SET ROLE ALL;
SET ROLE NONE;
SHOW GRANTS FOR 'app'@'10.0.0.%' USING 'role_rw';
6.4 密码策略组件
INSTALL COMPONENT 'file://component_validate_password';
SHOW VARIABLES LIKE 'validate_password%';
SET PERSIST validate_password.policy = MEDIUM; -- LOW/MEDIUM/STRONG
SET PERSIST validate_password.length = 12;
SET PERSIST validate_password.mixed_case_count = 1;
SET PERSIST validate_password.special_char_count = 1;
版本差异:8.0 用
INSTALL PLUGIN validate_password SONAME 'validate_password.so';8.0.14 起推荐组件方式INSTALL COMPONENT,参数前缀也从validate_password_变成validate_password.。
6.5 安全基线
# my.cnf
bind-address=10.0.0.11 # 只监听内网,别 0.0.0.0 裸奔
local_infile=OFF # 禁 LOAD DATA LOCAL,防客户端任意文件读取
skip_name_resolve=ON # 跳过反解,连接更快
require_secure_transport=ON # 强制 TLS(确认客户端支持后再开)
-- 清理匿名账号与空密码账号
SELECT user, host, plugin FROM mysql.user WHERE user='' OR authentication_string='';
DROP USER ''@'localhost';
-- 确认 root 只能本地登录
SELECT user, host FROM mysql.user WHERE user='root';
-- 只应出现 root@localhost;若有 root@'%' 立即处理
# TLS 证书(8.0+ 启动时自动生成自签证书到 datadir)
mysql -uroot -p -e "SHOW VARIABLES LIKE 'have_ssl';"
mysql -uroot -p --ssl-mode=REQUIRED -e "SHOW STATUS LIKE 'Ssl_cipher';"
7. 库表日常操作
7.1 库操作
CREATE DATABASE appdb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE DATABASE IF NOT EXISTS appdb CHARACTER SET utf8mb4;
DROP DATABASE appdb; -- 危险,无回收站
ALTER DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
SHOW DATABASES;
SHOW CREATE DATABASE appdb;
USE appdb;
SELECT DATABASE(), SCHEMA();
7.2 表操作
SHOW TABLES;
SHOW TABLES LIKE 'order%';
SHOW CREATE TABLE orders\G
DESC orders;
SHOW INDEX FROM orders;
SHOW TABLE STATUS LIKE 'orders'\G
CREATE TABLE orders (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT UNSIGNED NOT NULL,
amount DECIMAL(12,2) NOT NULL DEFAULT '0.00',
status TINYINT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_user_created (user_id, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
RENAME TABLE orders TO orders_old;
TRUNCATE TABLE orders; -- 危险,不可回滚
DROP TABLE orders; -- 危险
7.3 在线 DDL 与算法选择
-- 加列:8.0.12+ 支持 INSTANT,秒级完成
ALTER TABLE orders ADD COLUMN remark VARCHAR(255) DEFAULT NULL, ALGORITHM=INSTANT;
-- 加索引:INPLACE,仍会占 IO,建议低峰
ALTER TABLE orders ADD INDEX idx_status (status), ALGORITHM=INPLACE, LOCK=NONE;
-- 改列类型:可能 COPY,大表必须用工具
ALTER TABLE orders MODIFY COLUMN amount DECIMAL(14,2) NOT NULL, ALGORITHM=INPLACE, LOCK=NONE;
-- 先试跑,不真正执行(8.0+)
ALTER TABLE orders ADD INDEX idx_x (x), ALGORITHM=INSTANT;
-- 报错就看提示,换 INPLACE 或 COPY
版本差异:8.0.12+ 支持
INSTANT ADD COLUMN;8.0.29+ 支持INSTANT DROP COLUMN及在任意位置加列。8.4 的 INSTANT 覆盖面更广,但改列类型、改字符集仍然要重建表。 百万行以上的表,优先用pt-online-schema-change或gh-ost,不要直接ALTER。
7.4 统计信息与碎片
ANALYZE TABLE orders; -- 更新统计信息,优化器依赖它
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 32 BUCKETS; -- 8.0+ 直方图
OPTIMIZE TABLE orders; -- InnoDB 会重建表,等于回收碎片,锁与 IO 大
ALTER TABLE orders ENGINE=InnoDB; -- 等价的在线重建方式
CHECK TABLE orders;
CHECKSUM TABLE orders;
REPAIR TABLE orders; -- 仅 MyISAM 有意义
8. 备份与恢复
8.1 备份策略选型
| 方式 | 粒度 | 锁与影响 | 适用 |
|---|---|---|---|
mysqldump |
库/表/全库 | --single-transaction 下 InnoDB 几乎无锁 |
中小库、逻辑备份、跨版本迁移 |
MySQL Shell util dump |
库/表 | 并行、压缩好 | 大库逻辑备份,8.0+ 推荐 |
| Clone Plugin | 整实例物理 | 需停写或加锁 | 快速搭从库、整实例搬迁 |
| XtraBackup | 整实例物理 | 热备 | 大数据量生产标准方案 |
| 文件系统快照 | 整实例 | 需短暂冻结点 | 云环境、LVM |
3-2-1 原则:至少 3 份副本、2 种介质、1 份异地;并且每季度做一次真实恢复演练——没验证过的备份不算备份。
8.2 mysqldump
# 全库(含建库语句),InnoDB 一致性快照,不锁表
mysqldump -uroot -p \
--single-transaction \
--quick \
--routines --triggers --events \
--set-gtid-purged=OFF \
--default-character-set=utf8mb4 \
--all-databases > /backup/all_$(date +%F).sql
# 单库
mysqldump -uroot -p --single-transaction --databases appdb > /backup/appdb.sql
# 单表
mysqldump -uroot -p --single-transaction appdb orders > /backup/orders.sql
# 只要结构
mysqldump -uroot -p --no-data --databases appdb > /backup/appdb_schema.sql
# 只要数据
mysqldump -uroot -p --no-create-info appdb > /backup/appdb_data.sql
# 压缩 + 分库并行
mysqldump -uroot -p --single-transaction --databases appdb | gzip > /backup/appdb.sql.gz
# 一致性要求高(有 MyISAM 表时才需要)
mysqldump -uroot -p --lock-all-tables --all-databases > /backup/all_locked.sql
关键参数说明:
| 参数 | 作用 |
|---|---|
--single-transaction |
开启可重复读事务,保证 InnoDB 一致性且不锁表 |
--quick |
逐行取,避免大表撑爆内存 |
--routines --triggers --events |
把存储过程、触发器、事件一起导出(默认不导) |
--set-gtid-purged=OFF |
导入到非 GTID 环境时必加,否则报错 |
--master-data=2 / --source-data=2 |
记录 binlog 位点(注释形式),搭从库用 |
--where="created_at>='2026-01-01'" |
条件导出 |
--ignore-table=appdb.logs |
排除大日志表 |
版本差异:
--master-data在 8.0.26+ 改名为--source-data,旧名仍兼容。mysqldump属于客户端工具,跨大版本使用要以低版本客户端导出、同版本或更高导入更稳。
恢复:
# 普通恢复
mysql -uroot -p < /backup/all_2026-11-05.sql
# 压缩包恢复
gunzip < /backup/appdb.sql.gz | mysql -uroot -p
# 恢复前临时关双写与唯一性检查(大幅提速,仅限导入窗口)
mysql -uroot -p -e "SET GLOBAL innodb_flush_log_at_trx_commit=2; SET GLOBAL sync_binlog=0;"
mysql -uroot -p appdb < /backup/appdb.sql
mysql -uroot -p -e "SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL sync_binlog=1;"
8.3 MySQL Shell 并行备份(大库推荐)
# 导出(并行 8 线程,zstd 压缩)
mysqlsh --uri root@localhost:3306 -- util dumpSchemas appdb \
--outputDir=/backup/dump \
--threads=8 \
--compression=zstd
# 全实例导出
mysqlsh --uri root@localhost:3306 -- util dumpInstance /backup/dump_inst --threads=8
# 导入
mysqlsh --uri root@localhost:3306 -- util loadDump /backup/dump --threads=8
# 只导数据/只导结构
mysqlsh --uri root@localhost:3306 -- util dumpSchemas appdb --outputDir=/b --ddlOnly
mysqlsh --uri root@localhost:3306 -- util dumpSchemas appdb --outputDir=/b --dataOnly
8.4 Clone Plugin(整实例物理克隆)
-- 安装插件(也可写 my.cnf: plugin-load-add=mysql_clone.so)
INSTALL PLUGIN clone SONAME 'mysql_clone.so';
SELECT * FROM information_schema.plugins WHERE plugin_name='clone';
-- 本地克隆到目录(目录必须不存在且为空)
CLONE LOCAL DATA DIRECTORY = '/backup/clone_20261105';
-- 远程克隆(在目标实例执行,会覆盖目标数据,危险)
CLONE INSTANCE FROM 'backup'@'10.0.0.11':3306 IDENTIFIED BY 'Backup#2026';
-- 监控进度
SELECT * FROM performance_schema.clone_progress;
SELECT * FROM performance_schema.clone_status\G
危险:
CLONE INSTANCE FROM会清空目标实例数据再覆盖。执行前确认连的是从库而不是主库。
8.5 XtraBackup 热备
# 全量备份
xtrabackup --backup --user=backup --password='Backup#2026' \
--target-dir=/backup/xtra/20261105 --parallel=4 --compress
# 准备(回放 redo,使数据一致)
xtrabackup --prepare --target-dir=/backup/xtra/20261105
# 恢复:停库 → 清空 datadir → 拷回 → 改权限 → 启库
systemctl stop mysqld
mv /data/mysql/data /data/mysql/data.bak
xtrabackup --copy-back --target-dir=/backup/xtra/20261105
chown -R mysql:mysql /data/mysql/data
systemctl start mysqld
# 增量备份(基于上一次全备)
xtrabackup --backup --target-dir=/backup/xtra/inc1 \
--incremental-basedir=/backup/xtra/20261105
版本必须对齐:XtraBackup 8.4 对应 MySQL 8.4,XtraBackup 8.0 对应 8.0。用错大版本会直接拒绝备份。MySQL 9.7 / 26.x 需使用支持对应版本的新版 XtraBackup,上线前先确认支持矩阵。
8.6 binlog 增量恢复(误删数据救火)
# 1) 找到误操作前的位置(全备文件里记录的位点)
head -30 /backup/all_2026-11-05.sql | grep -i 'CHANGE MASTER\|SOURCE_LOG'
# 2) 解析 binlog 定位误删语句的时间点
mysqlbinlog --base64-output=DECODE-ROWS -v \
/data/mysql/binlog/mysql-bin.000123 | grep -n -i 'delete from orders'
# 3) 恢复到误操作之前(按时间点)
mysqlbinlog --start-datetime="2026-11-05 09:00:00" \
--stop-datetime="2026-11-05 10:15:00" \
/data/mysql/binlog/mysql-bin.000123 | mysql -uroot -p
# 4) 按位置恢复
mysqlbinlog --start-position=12345678 --stop-position=12349999 \
/data/mysql/binlog/mysql-bin.000123 | mysql -uroot -p
建议:把
mysqlbinlog ... > /backup/binlog_restore.sql先落地,人工检查一遍再执行。直接管道进 mysql 等于把二次事故的可能性一起灌进去。
9. binlog 与主从复制
9.1 binlog 基础
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format'; -- ROW 为生产标准
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
SHOW BINARY LOGS;
SHOW MASTER STATUS\G -- 当前写入位点
SHOW BINLOG EVENTS IN 'mysql-bin.000123' LIMIT 20;
FLUSH BINARY LOGS; -- 切一个新文件
PURGE BINARY LOGS TO 'mysql-bin.000120'; -- 删到此文件之前
PURGE BINARY LOGS BEFORE '2026-11-01 00:00:00';
版本差异:8.0.22+ 用
SHOW REPLICA STATUS/SHOW BINARY LOG STATUS新语法,旧语法SHOW MASTER STATUS/SHOW SLAVE STATUS仍兼容但在逐步退场。写新脚本建议用新语法,兼容老实例时用旧语法。
9.2 主库配置
# 主库 my.cnf
server-id=1
log_bin=/data/mysql/binlog/mysql-bin
binlog_format=ROW
binlog_row_image=FULL
gtid_mode=ON
enforce_gtid_consistency=ON
sync_binlog=1
innodb_flush_log_at_trx_commit=1
binlog_expire_logs_seconds=604800
-- 复制账号
CREATE USER 'repl'@'10.0.0.%' IDENTIFIED BY 'Repl#2026';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.0.0.%';
9.3 搭建从库(GTID 方式,推荐)
# 1) 主库做一致性备份(带位点)
mysqldump -uroot -p --single-transaction --source-data=2 \
--set-gtid-purged=ON --all-databases > /backup/full.sql
# 2) 从库导入
mysql -uroot -p < /backup/full.sql
-- 3) 从库指向主库
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='10.0.0.11',
SOURCE_PORT=3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='Repl#2026',
SOURCE_AUTO_POSITION=1;
-- 4) 启动与检查
START REPLICA;
SHOW REPLICA STATUS\G
关键列判读:
| 列 | 期望值 | 异常含义 |
|---|---|---|
Replica_IO_Running |
Yes |
Connecting = 网络/账号/防火墙问题 |
Replica_SQL_Running |
Yes |
No = 回放报错,看 Last_SQL_Error |
Seconds_Behind_Source |
0~5 | 持续增长 = 大事务、无主键、从库性能不足 |
Last_IO_Error / Last_SQL_Error |
空 | 有内容先读原文再动手 |
Retrieved_Gtid_Set / Executed_Gtid_Set |
差值小 | 差集大说明回放积压 |
版本差异:5.7 与 8.0.22 之前用
CHANGE MASTER TO、START SLAVE、SHOW SLAVE STATUS;8.0.23+ 统一为SOURCE/REPLICA术语。新旧语法在 8.4 中都可用,但文档与新工具已全面转向新语法。
9.4 复制运维常用
STOP REPLICA;
START REPLICA;
STOP REPLICA SQL_THREAD;
START REPLICA SQL_THREAD;
SHOW REPLICA STATUS\G
-- 跳过一条错误(GTID 模式下)
SET GTID_NEXT='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:12345';
BEGIN; COMMIT;
SET GTID_NEXT='AUTOMATIC';
START REPLICA;
-- 传统位点模式下跳过 N 个事件
STOP REPLICA; SET GLOBAL sql_replica_skip_counter=1; START REPLICA;
-- 重置复制(换主库前)
STOP REPLICA;
RESET REPLICA ALL;
-- 只读从库
SET GLOBAL super_read_only=ON;
SET GLOBAL read_only=ON;
原则:跳过事务是最后手段。跳之前必须搞清楚这条事务改了什么,用
mysqlbinlog把对应 GTID 的事件解出来人工比对,否则主从数据会静默不一致。
9.5 延迟与并行复制
SHOW VARIABLES LIKE 'replica_parallel_workers'; -- 建议 = CPU 核数
SHOW VARIABLES LIKE 'replica_parallel_type'; -- LOGICAL_CLOCK
SHOW VARIABLES LIKE 'replica_preserve_commit_order';
SHOW PROCESSLIST; -- 看 SQL 线程在跑什么
replica_parallel_workers=8
replica_parallel_type=LOGICAL_CLOCK
replica_preserve_commit_order=ON
延迟三大根因:大事务(一次删百万行)、大表无主键导致 ROW 回放全表扫、从库单线程回放。前两个改业务,第三个加
replica_parallel_workers。
10. 日志体系
10.1 日志类型与位置
| 日志 | 默认位置 | 开启方式 |
|---|---|---|
| 错误日志 | $DATADIR/*.err(RHEL 包为 /var/log/mysqld.log) |
默认开启,log_error 指定 |
| 慢查询日志 | $DATADIR/*-slow.log |
slow_query_log=ON |
| 通用日志 | $DATADIR/*.log |
general_log=ON,生产禁开 |
| binlog | $DATADIR/*-bin.* |
log_bin |
| relay log | $DATADIR/*-relay-bin.* |
从库自动 |
SHOW VARIABLES LIKE 'log_error';
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'general_log%';
SHOW VARIABLES LIKE 'log_bin';
10.2 错误日志
tail -f /var/log/mysqld.log
grep -i -E 'error|warning|aborted' /var/log/mysqld.log | tail -50
grep -i 'temporary password' /var/log/mysqld.log
journalctl -u mysqld -p err --no-pager
常见关键字对照:
| 关键字 | 含义 |
|---|---|
[ERROR] InnoDB: Unable to lock ./ibdata1 |
已有实例在跑,或 pid 文件残留 |
[ERROR] Do you already have another mysqld server running on port |
端口冲突 |
[Warning] IP address ... could not be resolved |
DNS 反解慢,加 skip_name_resolve |
[ERROR] Too many connections |
连接数打满 |
[ERROR] Table './db/t' is marked as crashed |
表损坏,需 REPAIR/恢复 |
Aborted connection ... (Got an error reading communication packets) |
客户端异常断开或超时 |
10.3 慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = OFF; -- 开了会刷爆日志
SET GLOBAL slow_query_log_file = '/data/mysql/logs/slow.log';
SHOW VARIABLES LIKE 'slow_query_log_file';
# 自带工具统计
mysqldumpslow -s t -t 20 /data/mysql/logs/slow.log # 按总耗时 TOP20
mysqldumpslow -s c -t 20 /data/mysql/logs/slow.log # 按次数
# 业界标准:pt-query-digest
pt-query-digest /data/mysql/logs/slow.log > /tmp/slow_report.txt
pt-query-digest --since '2026-11-01' --until '2026-11-05' /data/mysql/logs/slow.log
10.4 日志清理与轮转
# 用 logrotate 管理错误日志与慢日志
cat > /etc/logrotate.d/mysql <<'EOF'
/data/mysql/logs/*.log {
daily
rotate 14
missingok
compress
delaycompress
notifempty
copytruncate
}
EOF
logrotate -d /etc/logrotate.d/mysql # 干跑验证
-- binlog 用 SQL 清理,不要 rm 文件(会破坏索引文件)
PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY);
危险:手工
rmbinlog 文件而不走PURGE,会让mysql-bin.index与实际文件不一致,可能导致启动失败。清理一律用PURGE BINARY LOGS。
11. 性能诊断与优化
11.1 一眼看现状
SHOW GLOBAL STATUS LIKE 'Uptime';
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Threads_running';
SHOW GLOBAL STATUS LIKE 'Questions';
SHOW GLOBAL STATUS LIKE 'Slow_queries';
SHOW GLOBAL STATUS LIKE 'Aborted_connects';
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
SHOW ENGINE INNODB STATUS\G
QPS / TPS 手算:
-- QPS ≈ Questions / Uptime
SELECT ROUND(Questions / Uptime, 2) AS qps FROM
(SELECT VARIABLE_VALUE+0 AS Questions FROM performance_schema.global_status WHERE VARIABLE_NAME='Questions') a,
(SELECT VARIABLE_VALUE+0 AS Uptime FROM performance_schema.global_status WHERE VARIABLE_NAME='Uptime') b;
11.2 当前连接与正在执行的 SQL
SHOW FULL PROCESSLIST;
SELECT id, user, host, db, command, time, state, LEFT(info,120) AS sql
FROM information_schema.processlist
WHERE command <> 'Sleep'
ORDER BY time DESC;
-- 8.0+ 更细:当前语句、等待事件、事务年龄
SELECT t.PROCESSLIST_ID, t.PROCESSLIST_USER, t.PROCESSLIST_TIME,
t.PROCESSLIST_STATE, e.EVENT_NAME, LEFT(t.PROCESSLIST_INFO,100) AS sql
FROM performance_schema.threads t
LEFT JOIN performance_schema.events_waits_current e ON e.THREAD_ID=t.THREAD_ID
WHERE t.PROCESSLIST_ID IS NOT NULL AND t.PROCESSLIST_COMMAND <> 'Sleep';
# 杀连接 / 杀语句
mysqladmin -uroot -p processlist
mysqladmin -uroot -p kill 12345
KILL 12345; -- 杀连接
KILL QUERY 12345; -- 只杀当前语句,连接保留
注意:
KILL不是立即生效,MySQL 在安全点才中断。大事务回滚可能比执行更久,杀完要观察SHOW PROCESSLIST里是否还处于Rolling back。
11.3 锁与阻塞
-- 谁在等谁(8.0+)
SELECT * FROM sys.innodb_lock_waits\G
SELECT
r.trx_id AS waiting_trx, r.trx_mysql_thread_id AS waiting_thread,
r.trx_query AS waiting_query,
b.trx_id AS blocking_trx, b.trx_mysql_thread_id AS blocking_thread,
b.trx_query AS blocking_query
FROM performance_schema.data_lock_waits w
JOIN information_schema.innodb_trx b ON b.trx_id = w.BLOCKING_ENGINE_TRANSACTION_ID
JOIN information_schema.innodb_trx r ON r.trx_id = w.REQUESTING_ENGINE_TRANSACTION_ID;
-- 当前锁明细
SELECT * FROM performance_schema.data_locks;
SELECT * FROM information_schema.innodb_trx\G
版本差异:5.7 用
information_schema.innodb_locks+innodb_lock_waits(8.0 已移除),8.0+ 改用performance_schema.data_locks/data_lock_waits。老监控脚本升级时会直接报"表不存在"。
11.4 执行计划
EXPLAIN SELECT * FROM orders WHERE user_id=100 AND status=1;
EXPLAIN FORMAT=JSON SELECT ...;
EXPLAIN ANALYZE SELECT ...; -- 8.0.18+,真实执行并给出实际耗时/行数
SHOW WARNINGS; -- 看优化器改写后的 SQL
SHOW PROFILES; -- 已弃用,用 performance_schema 代替
EXPLAIN 关键列判读:
| 列 | 危险信号 |
|---|---|
type |
ALL(全表扫)、index(全索引扫)需优化;ref/range/eq_ref 较好 |
rows |
估算行数远大于返回行数,统计信息可能过期,跑 ANALYZE TABLE |
Extra |
Using temporary、Using filesort、Using join buffer 是需要关注的三项 |
key |
NULL 表示没走索引 |
11.5 InnoDB 关键指标
-- buffer pool 命中率,应 > 99%
SELECT
ROUND(100 - (SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME='Innodb_buffer_pool_reads') * 100 /
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME='Innodb_buffer_pool_read_requests'), 4) AS hit_pct;
-- 脏页比例,持续接近 100% 说明刷脏跟不上
SELECT
(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_dirty') /
(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_total') * 100 AS dirty_pct;
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_wait_free'; -- 非 0 说明 buffer pool 不够
SHOW GLOBAL STATUS LIKE 'Innodb_row_lock_time_avg';
SHOW GLOBAL STATUS LIKE 'Innodb_row_lock_waits';
SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks';
-- 表级 IO 热点
SELECT * FROM sys.schema_table_statistics ORDER BY total_latency DESC LIMIT 10;
SELECT * FROM sys.io_global_by_file_by_bytes ORDER BY total DESC LIMIT 10;
SELECT * FROM sys.statement_analysis ORDER BY total_latency DESC LIMIT 10;
11.6 服务器层排障
top -H -p $(pgrep -x mysqld) # 看哪个线程吃 CPU
pidstat -p $(pgrep -x mysqld) 1
iostat -x 1 5 # 看 %util、await
vmstat 1 5
free -h
dmesg | grep -i -E 'oom|killed process'
OOM 判定:
dmesg出现Out of memory: Killed process ... (mysqld),说明被内核 OOM Killer 干掉,不是 MySQL 自己崩。要么降innodb_buffer_pool_size,要么加内存,要么限制容器 memory limit。
12. 空间与容量管理
12.1 库表大小排行
SELECT table_schema, table_name,
ROUND((data_length+index_length)/1024/1024, 2) AS total_mb,
ROUND(data_length/1024/1024, 2) AS data_mb,
ROUND(index_length/1024/1024, 2) AS index_mb,
table_rows
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','sys','performance_schema','information_schema')
ORDER BY (data_length+index_length) DESC
LIMIT 20;
-- 按库汇总
SELECT table_schema,
ROUND(SUM(data_length+index_length)/1024/1024/1024, 2) AS total_gb
FROM information_schema.tables
GROUP BY table_schema
ORDER BY total_gb DESC;
table_rows 是估算值,InnoDB 下可能偏差很大;要精确行数用 SELECT COUNT(*),或在 8.0+ 用 information_schema.tables 配合 ANALYZE TABLE 刷新。
12.2 磁盘占用盘点
df -h
du -sh /data/mysql/* | sort -h
du -sh /data/mysql/binlog/*
ls -lh /data/mysql/data/ | sort -k5 -h | tail -20
常见"磁盘莫名满了"的元凶,按概率排序:
- binlog 堆积:
SHOW BINARY LOGS;看总量,binlog_expire_logs_seconds是否被调大;从库长期断开时主库 binlog 无法清理。 - undo 表空间膨胀:长事务不提交,
ibdata/undo_001疯长。 - 慢日志/通用日志:
general_log误开,一天几十 G。 - relay log:从库回放卡住后持续堆积。
- ibtmp1:大查询临时表空间,重启才回收。
- 大表碎片:
OPTIMIZE TABLE可回收,但需要额外等量空间。
12.3 空间回收
-- 查看 undo 与临时表空间
SELECT * FROM information_schema.innodb_tablespaces WHERE name LIKE '%undo%';
SELECT @@innodb_undo_tablespaces, @@innodb_undo_log_truncate;
-- 查看长事务(undo 无法回收的头号原因)
SELECT trx_id, trx_state, trx_started,
TIMESTAMPDIFF(MINUTE, trx_started, NOW()) AS minutes,
trx_rows_locked, LEFT(trx_query,100) AS sql
FROM information_schema.innodb_trx
ORDER BY trx_started;
-- 回收表空间(会重建表,务必低峰)
ALTER TABLE big_logs ENGINE=InnoDB;
OPTIMIZE TABLE big_logs;
# 收缩 ibdata(需重新初始化,成本高,仅在无 file-per-table 时才值得)
# 正常情况请保持 innodb_file_per_table=ON,让每表独立表空间
危险操作顺序:
DROP TABLE/TRUNCATE后磁盘不降是正常现象(file-per-table 会释放,但 ibdata 不会缩)。不要为了省空间去动ibdata1。
13. 高可用:MGR / InnoDB Cluster
13.1 三种方案对比
| 方案 | 一致性 | 自动故障切换 | 复杂度 | 适用 |
|---|---|---|---|---|
| 传统主从(异步/半同步) | 最终一致 | 需外部组件(MHA、Orchestrator) | 中 | 读扩展、已有架构 |
| MGR(Group Replication) | 多数派确认 | 内建 | 中高 | 3 节点金融级 |
| InnoDB Cluster(MGR + Shell + Router) | 多数派确认 | 内建 + 路由 | 高 | 新建生产集群推荐 |
13.2 MGR 最小配置(三节点)
# 每个节点,server-id 与 loose-group_replication_local_address 各不相同
server-id=1
gtid_mode=ON
enforce_gtid_consistency=ON
binlog_checksum=NONE
log_replica_updates=ON
binlog_format=ROW
plugin-load-add=group_replication.so
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot=OFF
group_replication_local_address="10.0.0.11:33061"
group_replication_group_seeds="10.0.0.11:33061,10.0.0.12:33061,10.0.0.13:33061"
group_replication_bootstrap_group=OFF
group_replication_single_primary_mode=ON
group_replication_enforce_update_everywhere_checks=OFF
-- 首节点引导
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;
-- 其余节点加入
START GROUP_REPLICATION;
-- 检查
SELECT * FROM performance_schema.replication_group_members;
SELECT * FROM performance_schema.replication_group_member_stats\G
顺序不能错:
group_replication_bootstrap_group=ON只能在第一个节点、且只执行一次。两个节点同时 bootstrap 会脑裂成两个单节点组,恢复非常麻烦。
13.3 InnoDB Cluster(MySQL Shell)
# 1) 校验并配置实例(会提示改配置、必要时重启)
mysqlsh --uri root@10.0.0.11:3306 --js
dba.configureInstance('root@10.0.0.11:3306')
dba.configureInstance('root@10.0.0.12:3306')
dba.configureInstance('root@10.0.0.13:3306')
// 2) 创建集群
var c = dba.createCluster('prodCluster')
c.status()
// 3) 加节点(自动 clone)
c.addInstance('root@10.0.0.12:3306', {recoveryMethod:'clone'})
c.addInstance('root@10.0.0.13:3306', {recoveryMethod:'clone'})
// 4) 日常
c.status({extended:true})
c.describe()
c.removeInstance('root@10.0.0.13:3306')
c.setPrimaryInstance('root@10.0.0.12:3306') // 手动切主
c.rescan()
dba.rebootClusterFromCompleteOutage() // 全组宕机后拉起
# Router 引导(应用连 Router 的 6446 读写 / 6447 只读)
mysqlrouter --bootstrap root@10.0.0.11:3306 --user=mysqlrouter
systemctl enable --now mysqlrouter
14. 升级与迁移
14.1 升级路径
5.7 ──► 8.0 ──► 8.4 LTS ──► 9.7 LTS ──► 26.x(Innovation,可选)
规则:
- 不能跨 LTS 大跳。8.0 → 9.7 必须经 8.4,官方明确不支持一步到位。
- 不支持降级。升级前必须留可回退的物理备份 + 旧版本二进制。
- 小版本内可以直接升(8.4.10 → 8.4.11)。
- 从 8.0 升 8.4 前,先处理认证插件问题(
mysql_native_password在 8.4 默认禁用),否则老应用全部登录失败。
14.2 升级前检查(必做)
# MySQL Shell 官方升级检查器,输出兼容性问题清单
mysqlsh --uri root@localhost:3306 -- util checkForServerUpgrade
mysqlsh --uri root@localhost:3306 -- util checkForServerUpgrade --outputFormat=JSON --outputFile=/tmp/upgrade.json
# 手工补充检查
mysql -uroot -p -e "SELECT user,host,plugin FROM mysql.user;"
mysql -uroot -p -e "SELECT * FROM information_schema.tables WHERE table_collation='utf8mb3_general_ci';"
mysql -uroot -p -e "SHOW VARIABLES LIKE '%innodb_file_format%';" # 8.0 已移除
mysql -uroot -p -e "SHOW VARIABLES LIKE 'sql_mode';"
util checkForServerUpgrade 会检查:废弃/移除的参数、保留字冲突、utf8mb3 用法、过长的索引、不支持的分区、认证插件、GTID 一致性等。
14.3 就地升级(in-place)
# 1) 全量物理备份(这一步不能省)
xtrabackup --backup --target-dir=/backup/pre_upgrade_$(date +%F) --user=backup -p
# 2) 记录当前版本与参数快照
mysql -uroot -p -e "SHOW VARIABLES;" > /backup/vars_before.txt
mysql -uroot -p -e "SELECT VERSION();" >> /backup/vars_before.txt
# 3) 停库
systemctl stop mysqld
# 4) 替换二进制(RPM 方式:先把仓库切到 8.4 系列,再升级已安装包)
dnf config-manager --disable mysql-8.0-community 2>/dev/null || true
dnf config-manager --enable mysql-8.4-lts-community
dnf update -y mysql-community-server mysql-community-client mysql-community-common
# 或二进制方式:软链指向新目录
# 5) 启动,8.0.16+ 会自动执行数据字典升级
systemctl start mysqld
# 6) 验证
mysql -uroot -p -e "SELECT VERSION();"
tail -100 /var/log/mysqld.log | grep -i -E 'error|upgrade'
版本差异:
mysql_upgrade命令在 8.0.16 起已废弃、8.4 中已移除。8.0.16+ 由服务端启动时自动升级数据字典;若需强制重跑,用mysqld --upgrade=FORCE(8.0.16+)。老教程里的mysql_upgrade -uroot -p在 8.4 上会直接 command not found。
14.4 逻辑迁移(跨云/跨大版本最稳)
# 源库导出
mysqlsh --uri root@old:3306 -- util dumpInstance /backup/migrate --threads=8
# 目标库导入
mysqlsh --uri root@new:3306 -- util loadDump /backup/migrate --threads=8
跨版本迁移建议用 MySQL Shell dump/load 而不是 mysqldump:它会自动处理字符集、GTID、并行导入,并且对 8.0→9.7 的兼容性更好。
14.5 回退
# 回退前提:旧版二进制还在、旧数据目录的物理备份还在
systemctl stop mysqld
rm -rf /data/mysql/data
xtrabackup --copy-back --target-dir=/backup/pre_upgrade_2026-11-05
chown -R mysql:mysql /data/mysql/data
# 把软链指回旧版本
ln -sfn /usr/local/mysql-8.0.46 /usr/local/mysql
systemctl start mysqld
关键:数据字典升级后低版本无法启动(会报 "data dictionary is of a higher version")。所以回退只能靠升级前的物理备份,不能只换回二进制。这就是为什么第 1 步不能省。
15. 高频故障速查
15.1 连不上数据库
| 现象 | 排查顺序 |
|---|---|
Can't connect to MySQL server (111) |
服务是否起 → ss -lntp | grep 3306 → 防火墙/安全组 → bind-address |
Can't connect ... (2) socket 不存在 |
socket 路径不对 → SHOW VARIABLES LIKE 'socket' → 用 -S 指定 |
Access denied for user |
账号是否存在 → host 匹配(localhost vs 127.0.0.1)→ 密码 → 插件 |
Too many connections |
连接泄漏 → 连接池配置 → max_connections → 临时救火 |
Host 'x' is blocked |
max_connect_errors 触发 → FLUSH HOSTS |
| SSL 相关报错 | --ssl-mode=DISABLED 临时验证,再查证书 |
-- 连接数救火
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';
SET GLOBAL max_connections = 2000;
FLUSH HOSTS;
# 客户端插件不匹配时临时绕过(仅排障,不要写进生产配置)
mysql -uroot -p --ssl-mode=DISABLED
mysql -uroot -p --get-server-public-key
15.2 忘记 root 密码
systemctl stop mysqld
mysqld_safe --skip-grant-tables --skip-networking &
mysql -uroot
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'New#Pass2026';
mysqladmin -uroot -p shutdown
systemctl start mysqld
注意:
--skip-grant-tables期间任何本地用户都能无密登录,必须同时加--skip-networking并尽快完成。改完必须重启,不要用FLUSH PRIVILEGES直接放开。
15.3 表损坏 / 无法启动
# 先看错误日志,确认是哪张表、什么错
grep -i -E 'corrupt|crashed|checksum' /var/log/mysqld.log | tail -30
CHECK TABLE appdb.orders;
REPAIR TABLE appdb.orders; -- 仅 MyISAM 有效
InnoDB 损坏时逐级放开恢复模式(1 最轻,6 最危险):
[mysqld]
innodb_force_recovery=1
# 能启动就立刻 mysqldump 导出,再重建实例导入
mysqldump -uroot -p --single-transaction --all-databases > /backup/emergency.sql
危险:
innodb_force_recovery >= 4时表变为只读且可能丢失数据,6会跳过 redo 回放。只在"数据不要了也要把库拉起来"的场景用,用完立刻改回 0。
15.4 主从延迟/中断
SHOW REPLICA STATUS\G
Last_SQL_Error 关键字 |
处理 |
|---|---|
Duplicate entry |
主从数据已不一致,先比对再决定跳过 |
Cannot add or update a child row |
外键冲突,检查 foreign_key_checks |
Unknown database |
从库缺库,补建或从主库同步 |
Error_code: 1062 |
同上,唯一键冲突 |
The slave is connecting using CHANGE MASTER TO ... |
正常连接中,等待 |
Got fatal error 1236 |
binlog 被清理,需重新做全量 |
15.5 磁盘满
df -h
du -sh /data/mysql/* | sort -h | tail
ls -lh /data/mysql/binlog/ | tail
SHOW BINARY LOGS;
PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY);
急救顺序:清 binlog(用 PURGE)→ 清慢日志/错误日志 → 清 relay log(RESET REPLICA ALL 谨慎)→ 扩盘。不要在磁盘满时执行 OPTIMIZE/ALTER,它们需要额外空间。
15.6 时区不对
SELECT @@system_time_zone, @@global.time_zone, @@session.time_zone, NOW(), UTC_TIMESTAMP();
# my.cnf 固定偏移(不需要时区表)
default-time-zone='+08:00'
# 需要 named timezone 时导入时区表
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -uroot -p mysql
SET GLOBAL time_zone='Asia/Shanghai';
SELECT CONVERT_TZ(NOW(),'UTC','Asia/Shanghai');
注意:
default-time-zone只影响新连接;已有连接需SET SESSION time_zone。另外TIMESTAMP列会随会话时区转换,DATETIME不会——这是两列类型最本质的区别。
15.7 字符集乱码
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
SHOW FULL COLUMNS FROM appdb.orders; -- 看列的 Collation
修复已乱码数据(先备份,再改):
ALTER TABLE appdb.orders CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
判断技巧:
SHOW VARIABLES里character_set_client/connection/results三者都应是utf8mb4。若列是latin1而连接是utf8mb4,双写转换就会出问题。改字符集前必须备份,CONVERT TO不可逆。
16. 危险命令与避坑清单
16.1 绝对不能在生产随手敲的命令
| 命令 | 后果 | 防护 |
|---|---|---|
DROP DATABASE <db> |
整库消失,无回收站 | 生产禁用;sql_safe_updates 无法拦截,只能靠权限 |
DROP TABLE / TRUNCATE |
数据即刻清空,不可回滚 | 收回业务账号 DDL 权限 |
DELETE FROM t;(无 WHERE) |
全表删,大事务撑爆 undo | SET sql_safe_updates=1 强制带条件 |
UPDATE t SET c=1;(无 WHERE) |
全表改,锁表+主从延迟 | 同上 |
PURGE BINARY LOGS 误删 |
从库断链,只能重做全量 | 先确认从库位点 |
kill -9 mysqld |
崩溃恢复、binlog 可能丢 | 用 mysqladmin shutdown |
innodb_force_recovery=6 |
跳过 redo,数据可能丢 | 先备份再调,用完归 0 |
FLUSH TABLES WITH READ LOCK |
全库只读,业务全停 | 备份工具会自动加,手工别乱用 |
ALTER TABLE 大表直接跑 |
长时间锁表/IO 打满 | 用 ALGORITHM=INSTANT 或 gh-ost |
rm 数据目录/binlog 文件 |
实例报废 | 清理只走 PURGE,删除只走 DROP |
16.2 sql_safe_updates
SET SESSION sql_safe_updates = 1;
-- 之后 UPDATE/DELETE 必须带索引条件,否则报错
UPDATE orders SET status=0 WHERE id=1; -- OK
DELETE FROM orders; -- 报错,被拦住
16.3 变更前检查清单
# 1) 确认连的是哪个实例(防止手滑连生产)
mysql -uroot -p -e "SELECT @@hostname, @@port, @@datadir;"
# 2) 备份(DDL 前至少做结构+数据快照)
mysqldump -uroot -p --single-transaction --databases <db> > /backup/pre_change.sql
# 3) 看表多大(超过 500 万行就要评估在线 DDL 方案)
mysql -uroot -p -e "SELECT table_name, table_rows, ROUND((data_length+index_length)/1024/1024) mb FROM information_schema.tables WHERE table_schema='<db>';"
# 4) 看有没有长事务与锁等待
mysql -uroot -p -e "SELECT * FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 5;"
# 5) 低峰执行 + 观察主从延迟
mysql -uroot -p -e "SHOW REPLICA STATUS\G" | grep Seconds_Behind
17. 附录:常用 SQL 与参数速查
17.1 一分钟巡检脚本
#!/usr/bin/env bash
# 用法:./mysql_health.sh (依赖 ~/.my.cnf 免密)
set -euo pipefail
mysql -N -B -e "
SELECT '版本', VERSION()
UNION ALL SELECT '运行时长(小时)', ROUND(VARIABLE_VALUE/3600,1) FROM performance_schema.global_status WHERE VARIABLE_NAME='Uptime'
UNION ALL SELECT 'QPS', ROUND((SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Questions')/
(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Uptime'),1)
UNION ALL SELECT '当前连接', VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Threads_connected'
UNION ALL SELECT '活跃线程', VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Threads_running'
UNION ALL SELECT '最大连接数', VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Max_used_connections'
UNION ALL SELECT '慢查询数', VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Slow_queries'
UNION ALL SELECT '锁等待次数', VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_row_lock_waits'
UNION ALL SELECT '死锁次数', VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_deadlocks'
UNION ALL SELECT '数据总量(GB)', ROUND(SUM(data_length+index_length)/1024/1024/1024,2) FROM information_schema.tables;
"
echo "--- 最大的 3 张表 ---"
mysql -e "SELECT table_schema, table_name, ROUND((data_length+index_length)/1024/1024/1024,2) AS gb
FROM information_schema.tables
ORDER BY (data_length+index_length) DESC LIMIT 3;"
echo "--- 非 Sleep 会话 ---"
mysql -e "SELECT id,user,host,db,command,time,LEFT(info,80) sql FROM information_schema.processlist WHERE command<>'Sleep' ORDER BY time DESC LIMIT 10;"
echo "--- 长事务 ---"
mysql -e "SELECT trx_id,TIMESTAMPDIFF(MINUTE,trx_started,NOW()) min,trx_rows_locked,LEFT(trx_query,60) sql FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 5;"
17.2 常用单行命令
mysqladmin -uroot -p status # 一行看 QPS/TPS
mysqladmin -uroot -p extended-status | grep -E 'Threads_|Innodb_row_lock'
mysqladmin -uroot -p variables | grep -E 'max_connections|buffer_pool'
mysqladmin -uroot -p ping
mysqladmin -uroot -p processlist
mysqladmin -uroot -p kill <id>
mysqladmin -uroot -p flush-logs
mysqladmin -uroot -p flush-hosts
mysqladmin -uroot -p shutdown
17.3 常用 SQL 速查
-- 当前库表数量与大小
SELECT table_schema, COUNT(*) tables, ROUND(SUM(data_length+index_length)/1024/1024,1) mb
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','sys','performance_schema','information_schema')
GROUP BY table_schema ORDER BY mb DESC;
-- 找没有主键的表(复制延迟重灾区)
SELECT table_schema, table_name FROM information_schema.tables t
WHERE table_schema NOT IN ('mysql','sys','performance_schema','information_schema')
AND NOT EXISTS (SELECT 1 FROM information_schema.statistics s
WHERE s.table_schema=t.table_schema AND s.table_name=t.table_name AND s.index_name='PRIMARY');
-- 找冗余/重复索引(索引名不同但列相同)
SELECT table_schema, table_name, GROUP_CONCAT(index_name) idx, GROUP_CONCAT(column_name ORDER BY seq_in_index) cols
FROM information_schema.statistics
WHERE table_schema NOT IN ('mysql','sys','performance_schema','information_schema')
GROUP BY table_schema, table_name, cols HAVING COUNT(DISTINCT index_name) > 1;
-- 找最大的 10 个索引
SELECT table_schema, table_name, index_name, ROUND(stat_value*@@innodb_page_size/1024/1024,1) mb
FROM mysql.innodb_index_stats
WHERE stat_name='size' AND database_name NOT IN ('mysql','sys')
ORDER BY stat_value DESC LIMIT 10;
-- 表碎片率
SELECT table_schema, table_name,
ROUND(data_free/1024/1024,1) free_mb,
ROUND(data_free/(data_length+index_length+1)*100,1) frag_pct
FROM information_schema.tables
WHERE data_free > 100*1024*1024
ORDER BY data_free DESC;
-- 账号清单
SELECT user, host, plugin, account_locked, password_expired FROM mysql.user ORDER BY user, host;
-- 权限反查:谁有这个库的权限
SELECT GRANTEE, PRIVILEGE_TYPE FROM information_schema.schema_privileges WHERE TABLE_SCHEMA='appdb';
17.4 参数默认值速查(8.4)
| 参数 | 默认值 |
|---|---|
max_connections |
151 |
innodb_buffer_pool_size |
134217728(128M) |
innodb_redo_log_capacity |
104857600(100M) |
innodb_flush_log_at_trx_commit |
1 |
sync_binlog |
1 |
binlog_expire_logs_seconds |
2592000(30 天) |
character_set_server |
utf8mb4 |
collation_server |
utf8mb4_0900_ai_ci |
transaction_isolation |
REPEATABLE-READ |
default_authentication_plugin(8.0)/ authentication_policy(8.4) |
caching_sha2_password |
sql_mode |
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
local_infile |
OFF |
innodb_file_per_table |
ON |
slow_query_log |
OFF(生产必须手动开) |
17.5 常用端口
| 端口 | 用途 |
|---|---|
| 3306 | MySQL 默认端口 |
| 33060 | X Protocol(MySQL Shell / X DevAPI) |
| 33061 | MGR 组成员通信 |
| 6446 / 6447 | MySQL Router 读写 / 只读 |
17.6 关键目录
| 路径 | 内容 |
|---|---|
/var/lib/mysql |
RHEL 包默认 datadir |
/var/lib/mysql-files |
secure_file_priv 默认目录 |
/var/log/mysqld.log |
RHEL 包默认错误日志 |
/etc/my.cnf |
RHEL 系主配置 |
/etc/mysql/my.cnf |
Debian 系主配置 |
/etc/mysql/mysql.conf.d/ |
Debian 系分片配置目录 |
/etc/yum.repos.d/mysql-community.repo |
YUM 仓库配置 |
/etc/apt/sources.list.d/mysql.list |
APT 仓库配置 |
附:与工作区其他手册的配合
- 操作系统层(服务、磁盘、防火墙、SELinux):见
CentOS-7-10-常规运维指令手册.md/Ubuntu-常用运维指令手册.md - MySQL 装完后必须放行的端口:
firewall-cmd --add-service=mysql --permanent(RHEL)或ufw allow 3306/tcp(Ubuntu) - SELinux 开启时 datadir 变更需
semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?"+restorecon -Rv /data/mysql