为什么写这篇:MySQL 日常 80% 的运维问题都跟"用户/密码/远程连接"有关——ERROR 1130 远程拒绝、root 密码忘了、caching_sha2_password 客户端不兼容、InnoDB 起不来。本文把所有这些场景整理成可复用的 SOP。
适用读者:需要做 MySQL 账号管理、权限分配、生产排错的 DBA / 运维 / 后端。
前置知识:会用 mysql 客户端、了解 user/host 二元组的概念。
目录
- 账号体系:
user@host 二元组 - 创建用户与授权:GRANT / REVOKE
- 远程连接排错:ERROR 1130
- root 密码管理:重置 / 找回
- mysql_native_password vs caching_sha2_password
- InnoDB 启动崩溃:6 级 force_recovery
- 字符集与排序规则最佳实践
1. 账号体系:user@host 二元组
MySQL 的账号由 用户名 + 主机 共同决定——root@localhost 和 root@% 是两个独立的账号,密码可以不同。
| host 值 | 含义 |
|---|
localhost | 仅本地 socket 连接(不走 TCP) |
127.0.0.1 | 本地 TCP(不推荐,与 localhost 不同) |
10.0.0.1 | 单 IP |
10.0.0.% | 10.0.0 网段 |
10.0.0.0/255.255.255.0 | 等价于 10.0.0.%(MySQL 不支持 CIDR) |
% | 任意 IP(最不安全) |
host1, host2 | 多 IP 用逗号分隔 |
最佳实践:永远不要用 root@%。生产库至少分 3 个账号:
app_readonly@10.0.0.%:业务读账号,只 SELECTapp_rw@10.0.0.%:业务读写账号,限定特定库dba@10.0.0.%:DBA 管理账号,运维专用
2. 创建用户与授权:GRANT / REVOKE
2.1 创建用户
1
2
3
4
5
| -- 标准语法
CREATE USER 'username'@'host' IDENTIFIED BY 'password';
-- 示例
CREATE USER 'app_user'@'%' IDENTIFIED BY '{{REDACTED}}';
|
MySQL 5.7+ 默认密码策略是 MEDIUM:8 位以上、大小写 + 数字 + 符号。
2.2 授权(GRANT)
1
2
| -- 语法:grant 权限 on 库.表 to 'user'@'host'
GRANT ALL PRIVILEGES ON *.* TO 'app_user'@'%' WITH GRANT OPTION;
|
权限粒度从大到小:
| 粒度 | 语法 | 适用 |
|---|
| 全局 | *.* | DBA / 超级账号 |
| 库级 | industry_iot.* | 业务库应用 |
| 表级 | industry_iot.risk_task | 极小权限 |
| 列级 | (col1, col2) | 极少用(要 INSERT/SELECT 配合) |
完整权限列表(按常用度排序):
1
2
3
4
5
| ALL SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD,
SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES,
SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE,
REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE,
CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, CREATE ROLE, DROP ROLE
|
MySQL 8.0 还多了 动态权限(dynamic privileges):
1
2
3
4
5
6
7
8
| APPLICATION_PASSWORD_ADMIN, AUDIT_ADMIN, BACKUP_ADMIN, BINLOG_ADMIN,
BINLOG_ENCRYPTION_ADMIN, CLONE_ADMIN, CONNECTION_ADMIN, ENCRYPTION_KEY_ADMIN,
FLUSH_OPTIMIZER_COSTS, FLUSH_STATUS, FLUSH_TABLES, FLUSH_USER_RESOURCES,
GROUP_REPLICATION_ADMIN, INNODB_REDO_LOG_ARCHIVE, INNODB_REDO_LOG_ENABLE,
PERSIST_RO_VARIABLES_ADMIN, REPLICATION_APPLIER, REPLICATION_SLAVE_ADMIN,
RESOURCE_GROUP_ADMIN, RESOURCE_GROUP_USER, ROLE_ADMIN, SERVICE_CONNECTION_ADMIN,
SESSION_VARIABLES_ADMIN, SET_USER_ID, SHOW_ROUTINE, SYSTEM_USER,
SYSTEM_VARIABLES_ADMIN, TABLE_ENCRYPTION_ADMIN, XA_RECOVER_ADMIN
|
2.3 只授 CRUD(推荐生产)
1
2
3
4
| -- 业务账号:只允许 CRUD 业务库
GRANT SELECT, INSERT, UPDATE, DELETE
ON industry_iot_dev.*
TO 'app_user'@'10.0.0.%';
|
2.4 撤销权限
1
2
3
4
5
| -- 撤销所有权限 + 授权选项
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'app_user'@'%';
-- 撤销特定权限
REVOKE INSERT, UPDATE ON industry_iot_dev.* FROM 'app_user'@'10.0.0.%';
|
2.5 完整流程:创建 + 授权 + 刷新
1
2
3
4
5
6
7
8
9
10
11
12
13
| -- 1. 创建用户
CREATE USER 'app_user'@'%' IDENTIFIED BY '{{REDACTED}}';
-- 2. 授权
GRANT SELECT, INSERT, UPDATE, DELETE
ON industry_iot_dev.*
TO 'app_user'@'%';
-- 3. 刷新(必须有)
FLUSH PRIVILEGES;
-- 4. 验证:用新账号登录
-- mysql -h db_host -u app_user -p'{{REDACTED}}' industry_iot_dev
|
2.6 一次性创建 + 授权(with grant option)
1
| GRANT ALL PRIVILEGES ON industry_iot_dev.* TO 'dev'@'%' IDENTIFIED BY '{{REDACTED}}' WITH GRANT OPTION;
|
MySQL 8.0 已经不支持 GRANT ... IDENTIFIED BY 这种语法——必须先 CREATE USER 再 GRANT。这种"老语法"在 5.7 升级 8.0 时要全部改一遍。
3. 远程连接排错:ERROR 1130
1
| ERROR 1130 (HY000): Host 'xxx' is not allowed to connect to this MySQL server
|
原因:mysql.user 表里没有匹配 client_ip 的账号。
修法(生产推荐):
1
2
3
4
5
6
7
8
9
10
11
| -- 1. 用 mysql_native_password 创建远程专用账号
CREATE USER IF NOT EXISTS 'app_user'@'10.0.0.%'
IDENTIFIED WITH mysql_native_password BY '{{REDACTED}}';
-- 2. 授权(限定库,不给全局)
GRANT SELECT, INSERT, UPDATE, DELETE
ON industry_iot_dev.*
TO 'app_user'@'10.0.0.%';
-- 3. 刷新
FLUSH PRIVILEGES;
|
临时应急(仅测试用):
1
2
3
4
5
| -- 把 root 改成允许任意 IP
CREATE USER IF NOT EXISTS 'root'@'%'
IDENTIFIED WITH mysql_native_password BY '{{REDACTED}}';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
|
3.1 Navicat 客户端报错
Authentication plugin 'caching_sha2_password' cannot be loaded
→ 改用 mysql_native_password(见下文 §5)。
3.2 客户端连接慢(5+ 秒才连上)
useDNS=no 没设导致反向 DNS 查询慢。在 my.cnf 加:
1
2
| [mysqld]
skip-name-resolve
|
或对 MySQL 5.7+:
1
2
3
| [mysqld]
# 关闭反向 DNS 解析
skip-name-resolve
|
4. root 密码管理:重置 / 找回
4.1 在线改密码(MySQL 5.7+)
1
2
3
4
5
6
7
8
| -- 新版本(推荐)
ALTER USER 'root'@'localhost' IDENTIFIED BY '{{REDACTED}}';
-- 远程访问账号
ALTER USER 'root'@'%' IDENTIFIED BY '{{REDACTED}}';
-- 刷新
FLUSH PRIVILEGES;
|
4.2 旧版本兼容
1
2
3
4
5
6
7
8
9
| -- 5.6 / 5.7 老语法
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('{{REDACTED}}');
-- mysql_native_password 兼容
UPDATE user SET authentication_string = SHA1('{{REDACTED}}') WHERE user = 'root';
-- 允许任意 IP
UPDATE user SET host = '%' WHERE user = 'root';
FLUSH PRIVILEGES;
|
4.3 忘了密码(找回 SOP)
前提:能物理访问服务器 + 有 my.cnf 编辑权限。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| # 1. 停 MySQL
systemctl stop mysqld
# 2. 临时加 skip-grant-tables
vim /etc/my.cnf
# [mysqld]
# skip-grant-tables
# 3. 启动
systemctl start mysqld
# 4. 空密码登录
mysql -uroot
# 5. 清空 root 密码
USE mysql;
FLUSH PRIVILEGES;
UPDATE user SET authentication_string = '' WHERE user = 'root';
# 6. 退出,注释掉 skip-grant-tables
# 7. 重启
systemctl restart mysqld
# 8. 重新登录(空密码)
mysql -uroot
-- 9. 设置新密码
ALTER USER 'root'@'localhost' IDENTIFIED BY '{{REDACTED}}';
ALTER USER 'root'@'%' IDENTIFIED BY '{{REDACTED}}';
FLUSH PRIVILEGES;
|
4.4 mysqladmin 一行命令
1
2
| # 知道旧密码时最快
mysqladmin -uroot -p'{{OLD_PASSWORD}}' password '{{NEW_PASSWORD}}'
|
5. mysql_native_password vs caching_sha2_password
| 维度 | mysql_native_password | caching_sha2_password |
|---|
| 引入版本 | MySQL 5.6 之前 | MySQL 8.0(默认) |
| 算法 | SHA1 | SHA-256 + cache |
| 性能 | 较好 | 更快(首次验证后缓存) |
| 安全性 | 中(SHA1 已不推荐) | 高(不传明文密码) |
| 客户端兼容 | 全平台 | 8.0+ Connector、5.7.23+ xdevapi |
5.1 老客户端不兼容
老版本 Navicat (11/12)、JDBC 5.x、某些 ORM 框架连接时报:
1
| Authentication plugin 'caching_sha2_password' cannot be loaded
|
修法:
1
2
3
4
5
6
| -- 单个账号降级
ALTER USER 'app_user'@'10.0.0.%' IDENTIFIED WITH mysql_native_password BY '{{REDACTED}}';
FLUSH PRIVILEGES;
-- 全局默认改成 mysql_native_password
SET GLOBAL default_authentication_plugin = 'mysql_native_password';
|
新部署的项目应该用 caching_sha2_password——mysql_native_password 是历史包袱。
5.2 全局修改默认认证插件
1
2
3
| # /etc/my.cnf
[mysqld]
default_authentication_plugin = caching_sha2_password
|
改了之后已存在的用户不受影响,要批量改可以导出现有用户再 SET GLOBAL 重设。
6. InnoDB 启动崩溃:6 级 force_recovery
现象:
1
2
3
4
| [InnoDB] Unable to lock ./undo_001 error: 11
2025-01-03T02:52:18 [ERROR] [MY-012562] [InnoDB] We scanned the log up to ...
InnoDB: Assertion failure: log0log.cc:657:first_rec_group <= start_lsn - block_lsn
InnoDB: We intentionally generate a memory trap.
|
6.1 紧急修法
1
2
3
| # 1. 把有问题的 undo 文件备份
mv undo_001 undo_001.bak
cp -a undo_001.bak undo_001
|
6.2 force_recovery 6 级
1
2
3
| # /etc/my.cnf
[mysqld]
innodb_force_recovery = 6
|
| 值 | 含义 | 影响 |
|---|
| 1 (SRV_FORCE_IGNORE_CORRUPT) | 忽略 corrupt 页 | 可能丢数据 |
| 2 (SRV_FORCE_NO_BACKGROUND) | 阻止主线程 full purge | crash 风险 |
| 3 (SRV_FORCE_NO_TRX_UNDO) | 不执行事务回滚 | 丢未提交事务 |
| 4 (SRV_FORCE_NO_IBUF_MERGE) | 不执行插入缓冲合并 | 性能降 |
| 5 (SRV_FORCE_NO_UNDO_LOG_SCAN) | 不看重做日志 | 丢未提交事务 |
| 6 (SRV_FORCE_NO_LOG_REDO) | 不执行前滚 | 最后手段 |
使用原则:从 1 开始逐级试,能起来就用。6 起来后第一件事 mysqldump 全量导出——之后用正常模式重建库。
7. 字符集与排序规则最佳实践
7.1 建库时统一 utf8mb4
1
2
3
| CREATE DATABASE industry_iot_dev
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
|
7.2 建表时显式声明
1
2
3
4
5
6
7
8
9
10
| CREATE TABLE risk_task (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(64)
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NOT NULL DEFAULT '',
-- ...
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
|
7.3 utf8 vs utf8mb4
| 字符集 | 最大字符长度 | 实际能存 |
|---|
utf8 (MySQL 早期别名) | 3 字节 | 不支持 emoji、部分生僻字 |
utf8mb4 (MySQL 5.5.3+) | 4 字节 | 支持 emoji、所有 Unicode |
铁律:MySQL 的 utf8 不是真 utf8。新库必须用 utf8mb4。
7.4 排序规则
| Collation | 特点 |
|---|
utf8mb4_general_ci | 速度快,不严格按 Unicode 排序 |
utf8mb4_unicode_ci | 按 Unicode 标准排序,推荐 |
utf8mb4_bin | 按二进制比较(区分大小写) |
utf8mb4_0900_ai_ci | MySQL 8.0 新 UCA 9.0 算法(默认) |
建议:通用场景用 utf8mb4_unicode_ci(8.0 之前)或 utf8mb4_0900_ai_ci(8.0+)。
经验总结
| 主题 | 关键 SOP |
|---|
| 新用户 | CREATE USER + GRANT + FLUSH PRIVILEGES |
| 远程连接 | 不用 root@%;建 app_user@10.0.0.% 限定网段 |
| 密码忘了 | skip-grant-tables + 清空密码 + 重设 |
| caching_sha2 兼容 | 改用 mysql_native_password |
| InnoDB 崩了 | innodb_force_recovery=1~6 逐级试,6 起来立刻全量导出 |
| 字符集 | 永远 utf8mb4_unicode_ci |
下一步
- MySQL 索引优化:见《MySQL 索引优化实战》
- EXPLAIN + SQL 题解:见《MySQL 实战速查》
- 实时同步 Canal/Debezium:见《MySQL 实时同步实战》