Featured image of post MySQL 用户权限与安全实战:账号、密码、远程连接与排错

MySQL 用户权限与安全实战:账号、密码、远程连接与排错

本文整理 MySQL 用户与权限管理的全套实操:账号创建、GRANT/REVOKE 语法、远程连接排错(ERROR 1130)、root 密码重置、mysql_native_password 兼容性、InnoDB 崩溃恢复与字符集最佳实践。

为什么写这篇:MySQL 日常 80% 的运维问题都跟"用户/密码/远程连接"有关——ERROR 1130 远程拒绝、root 密码忘了、caching_sha2_password 客户端不兼容、InnoDB 起不来。本文把所有这些场景整理成可复用的 SOP。

适用读者:需要做 MySQL 账号管理、权限分配、生产排错的 DBA / 运维 / 后端。

前置知识:会用 mysql 客户端、了解 user/host 二元组的概念。

目录

  1. 账号体系:user@host 二元组
  2. 创建用户与授权:GRANT / REVOKE
  3. 远程连接排错:ERROR 1130
  4. root 密码管理:重置 / 找回
  5. mysql_native_password vs caching_sha2_password
  6. InnoDB 启动崩溃:6 级 force_recovery
  7. 字符集与排序规则最佳实践

1. 账号体系:user@host 二元组

MySQL 的账号由 用户名 + 主机 共同决定——root@localhostroot@% 是两个独立的账号,密码可以不同

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.%:业务读账号,只 SELECT
  • app_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 USERGRANT。这种"老语法"在 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_passwordcaching_sha2_password
引入版本MySQL 5.6 之前MySQL 8.0(默认
算法SHA1SHA-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 purgecrash 风险
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_ciMySQL 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 实时同步实战》
使用 Hugo 构建
主题 StackJimmy 设计