在 MySQL 数据库运维当中,账号和权限管理是安全环节里非常核心的一部分。数据库里存储着业务的核心数据,如果账号管控不当,出现弱密码、权限过大、远程 root 开放等问题,很容易造成数据泄露、误删、被入侵等严重事故。MySQL 8.0 在认证插件、密码策略、权限模型上和 5.7 版本有较大区别,本节主要围绕 MySQL8 的账号管理、密码策略、授权、回收权限、删除用户进行讲解。
1.1 密码策略
从 MySQL 8.0 开始,默认身份验证插件从 mysql_native_password 更改为 caching_sha2_password。 MySQL 5.7 的默认密码插件一直都是 mysql_native_password,它验证速度快,不需要加密连接传输密码。但是该插件底层依赖 SHA1 哈希算法,SHA1、MD5 这类算法已经被证实容易被破解,NIST 也已经建议不再使用 SHA1。
查看数据库密码相关变量:
show variables like "%password%";
| Variable_name | 说明 |
|---|---|
| caching_sha2_password_auto_generate_rsa_keys | 是否自动生成 RSA 密钥对文件 |
| caching_sha2_password_digest_rounds | 哈希迭代回合数,默认 5000 |
| caching_sha2_password_private_key_path | RSA 私钥文件路径 |
| caching_sha2_password_public_key_path | RSA 公钥文件路径 |
| default_password_lifetime | 密码过期时间,单位天,0 代表永不过期 |
| disconnect_on_expired_password | 密码过期后是否断开连接 |
| generated_random_password_length | 自动生成随机密码长度 |
| password_history | 禁止重复使用最近 N 次历史密码 |
| password_require_current | 修改密码是否需要输入旧密码 |
| password_reuse_interval | 多少天内不能重复使用旧密码 |
密码强度校验插件 component_validate_password,默认不会自动安装,直接查询会返回空结果:
SHOW VARIABLES LIKE 'validate_password%';
# Empty set (0.01 sec) 代表插件未安装
安装密码校验组件:
INSTALL COMPONENT 'file://component_validate_password';
安装完成后再次查看:
show variables like 'validate_password%';
| Variable_name | 说明 |
|---|---|
| validate_password.check_user_name | 禁止密码和用户名相同 |
| validate_password.dictionary_file | 弱密码字典文件路径 |
| validate_password.length | 密码最小长度,默认 8 |
| validate_password.mixed_case_count | 至少包含大小写字母总个数 |
| validate_password.number_count | 至少包含数字个数 |
| validate_password.policy | 密码安全等级 |
| validate_password.special_char_count | 至少包含特殊符号个数 |
密码强度等级(validate_password.policy)
0 / LOW:仅校验密码长度1 / MEDIUM(默认):长度 + 数字 + 大小写 + 特殊字符2 / STRONG:MEDIUM 全部规则 + 字典文件匹配弱密码
修改密码策略示例:
# 设置密码策略等级为LOW
set global validate_password.policy=low;
# 大小写字母最少0个
set global validate_password.mixed_case_count=0;
# 数字最少6个
set global validate_password.number_count=6;
# 特殊字符最少0个
set global validate_password.special_char_count=0;
# 密码最小长度6位
set global validate_password.length=6;
# 刷新权限,使配置生效
flush privileges;
修改用户密码语法:
alter user 'root'@'localhost' identified by '123456';
flush privileges;
注意:MySQL8 推荐使用
alter user修改密码,不推荐直接 update user 表的方式。
1.2 登录账户管理
MySQL8 权限管理原则:先创建用户,再分配权限 。 所有用户信息都保存在 mysql 库的 user 表中。
# 查看当前登录用户
select user();
# 切换到mysql系统库
use mysql;
# 查看库中表
show tables;
# 查看user表结构
desc user;
# 查询所有账号、登录主机、加密后的密码
select user,host,authentication_string from user;
1.3 新建登录账户
创建用户基础语法:
create user 'username'@'host' identified by 'password';
参数说明:
username:自定义用户名host:允许登录的来源地址localhost:仅本机登录192.168.1.%:该网段内主机可以登录%:任意远程地址都可以登录(生产慎用)
password:账号密码
示例:
create user 'dragon'@'localhost' identified by 'Dragon@123';
新创建的用户默认只有 USAGE 连接权限,几乎看不到业务数据库,需要手动授权。
1.4 账户授权
授权原则(生产必看)
- root 账号禁止使用
%远程登录,只保留localhost本地登录; - 业务应用账号、管理员账号分开;
- 最小权限原则:按需分配,一般业务账号只给 SELECT 查询权限,尽量不开 UPDATE、DELETE、DROP 高危权限;
- 密码复杂度符合安全策略;
- 定期清理闲置账号,回收或者直接删除。
查看用户权限
# 查看当前账号权限
show grants;
# 查看指定用户权限
show grants for 'dragon'@'localhost';
新用户默认只有连接权限:GRANT USAGE ON *.* TO dragon@localhost``
GRANT 授权语法
grant 权限列表 on 库名.表名 to '用户名'@'来源地址' [identified by '密码'];
- 权限列表:
select,insert,update,delete,create,drop,全部权限写all *.*:代表所有数据库下的所有表testdb.*:仅 testdb 库下面所有表testdb.t_user:仅 testdb 库中的 t_user 表
示例 1:创建 test1,授予查询所有库表权限
create user 'test1'@'localhost' identified by '123456';
grant select on *.* to 'test1'@'localhost';
示例 2:创建 test2,允许 192.168.56.% 网段登录,拥有 select、create 权限
create user 'test2'@'192.168.56.%' identified by '123456';
grant select,create on *.* to 'test2'@'192.168.56.%';
示例 3:all 权限和 with grant option 直接授予all权限不包含给其他用户授权的能力。
create user 'test3'@'%' identified by '123456';
grant all on *.* to 'test3'@'%';
此时 test3 尝试给其他账号授权会报错 Access denied。 如果需要该用户具备授权别人的能力,加上 with grant option:
grant all on *.* to 'test3'@'%' with grant option;
之后 test3 就可以新建用户、给其他账号分配权限。
补充:部分版本 root 执行授权报错,需要先给 root 赋予 system_user 权限
grant system_user on *.* to 'root'@'localhost';
1.5 回收权限
REVOKE 回收权限语法,和 grant 结构类似,关键字to改为from:
revoke 权限列表/all on 库名.表名 from '用户名'@'来源地址';
示例:
# 回收test4的select权限
revoke select on *.* from 'test4'@'%';
# 回收test3全部权限
revoke all on *.* from 'test3'@'%';
# 回收test2全部权限
revoke all on *.* from 'test2'@'192.168.56.%';
# 回收test1全部权限
revoke all on *.* from 'test1'@'localhost';
1.6 删除账户
删除用户语法:
drop user '用户名'@'访问主机名';
示例:
drop user 'test3'@'%';
drop user 'test4'@'%';
drop user 'test2'@'192.168.56.%';
drop user 'test1'@'localhost';
注意:删除用户必须带上 host 部分,
'test1'@'localhost'和'test1'@'%'是两个完全独立账号。