说明:DCL(Data Control Language,数据控制语言)用于管理数据库用户的权限和访问控制。本指南涵盖 MySQL 5.7 和 8.0 中的所有用户、角色和权限管理命令。
一、用户管理
1.1 创建用户
语法:
sql
CREATE USER [IF NOT EXISTS] '用户名'@'主机名'
IDENTIFIED BY '密码'
[DEFAULT ROLE 角色名]
[PASSWORD EXPIRE [NEVER | INTERVAL N DAY | DEFAULT]]
[ACCOUNT LOCK | UNLOCK];
主机名格式:
'localhost'- 仅允许本地连接'%'- 允许任意主机连接'192.168.1.%'- 允许特定网段'192.168.1.100'- 允许特定IP
示例:
sql
-- 基本创建
CREATE USER 'john'@'localhost' IDENTIFIED BY 'password123';
-- 存在则不重复创建(推荐)
CREATE USER IF NOT EXISTS 'app_user'@'%' IDENTIFIED BY 'AppPass456';
-- 带账户锁定(解锁后可用)
CREATE USER 'temp'@'localhost' IDENTIFIED BY 'temp' ACCOUNT LOCK;
-- 设置密码过期策略(90天后过期)
CREATE USER 'reporter'@'%' IDENTIFIED BY 'report' PASSWORD EXPIRE INTERVAL 90 DAY;
1.2 删除用户
语法:
sql
DROP USER [IF EXISTS] '用户名'@'主机名' [, '用户名'@'主机名'] ...;
示例:
sql
-- 删除单个用户
DROP USER 'john'@'localhost';
-- 安全删除(推荐)
DROP USER IF EXISTS 'old_user'@'%';
-- 批量删除多个用户
DROP USER 'user1'@'localhost', 'user2'@'192.168.1.%';
1.3 修改用户名(重命名用户)
语法:
sql
RENAME USER '旧用户名'@'旧主机名' TO '新用户名'@'新主机名';
示例:
sql
RENAME USER 'john'@'localhost' TO 'john_doe'@'%';
⚠️ 注意:MySQL 8.0 中已支持,5.7 也可用。重命名后原有权限会自动转移到新用户名上。
1.4 修改用户密码
方式一:ALTER USER(MySQL 5.7.6+,推荐)
sql
ALTER USER '用户名'@'主机名' IDENTIFIED BY '新密码';
方式二:SET PASSWORD(旧方式)
sql
-- 修改当前用户密码
SET PASSWORD = '新密码';
-- 修改指定用户密码(需要权限)
SET PASSWORD FOR '用户名'@'主机名' = '新密码';
方式三:使用旧版 PASSWORD() 函数(不推荐)
sql
SET PASSWORD FOR 'user'@'host' = PASSWORD('新密码');
方式四:mysqladmin 命令行
bash
mysqladmin -u root -p password '新密码'
示例:
sql
ALTER USER 'john'@'localhost' IDENTIFIED BY 'new_secure_pass';
SET PASSWORD FOR 'app_user'@'%' = 'new_app_pass';
1.5 密码过期管理
sql
-- 设置密码立即过期(下次登录强制修改)
ALTER USER 'user'@'host' PASSWORD EXPIRE;
-- 设置密码永不过期
ALTER USER 'user'@'host' PASSWORD EXPIRE NEVER;
-- 设置为默认过期策略(由 default_password_lifetime 决定)
ALTER USER 'user'@'host' PASSWORD EXPIRE DEFAULT;
-- 设置间隔天数后过期
ALTER USER 'user'@'host' PASSWORD EXPIRE INTERVAL 90 DAY;
1.6 锁定/解锁账户
sql
-- 锁定账户(禁止登录)
ALTER USER 'user'@'host' ACCOUNT LOCK;
-- 解锁账户
ALTER USER 'user'@'host' ACCOUNT UNLOCK;
1.7 查看所有用户
sql
-- MySQL 5.7/8.0
SELECT user, host, account_locked, password_expired FROM mysql.user;
-- 更详细的信息
SELECT user, host, authentication_string, password_last_changed,
password_lifetime, account_locked
FROM mysql.user;
1.8 查看当前登录用户
sql
SELECT CURRENT_USER(); -- 当前活动用户(权限对应的用户)
SELECT USER(); -- 连接时提供的用户名和主机
二、权限管理
2.1 权限级别
MySQL 权限从大到小分为:
- 全局权限 :
*.*所有数据库的所有对象 - 数据库级权限 :
db_name.*特定数据库的所有对象 - 表级权限 :
db_name.table_name特定表 - 列级权限 :
db_name.table_name(column1, column2,...)特定列 - 存储过程/函数权限 :
db_name.procedure_name - 代理用户权限 :
PROXY
2.2 授予权限(GRANT)
完整语法:
sql
GRANT 权限列表 ON 权限级别 TO '用户名'@'主机名'
[WITH GRANT OPTION]
[MAX_QUERIES_PER_HOUR count]
[MAX_UPDATES_PER_HOUR count]
[MAX_CONNECTIONS_PER_HOUR count]
[MAX_USER_CONNECTIONS count];
常用权限列表 :ALL [PRIVILEGES], SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER, REFERENCES, LOCK TABLES, CREATE TEMPORARY TABLES, EVENT, CREATE USER, FILE, PROCESS, RELOAD, REPLICATION SLAVE, REPLICATION CLIENT, SHOW DATABASES, SHUTDOWN, SUPER 等。
示例:
sql
-- 授予全局所有权限(管理员)
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;
-- 授予特定数据库的所有权限
GRANT ALL PRIVILEGES ON company_db.* TO 'app_user'@'%';
-- 授予只读权限(SELECT)
GRANT SELECT ON company_db.* TO 'reporter'@'localhost';
-- 授予表级权限
GRANT INSERT, UPDATE, DELETE ON company_db.users TO 'editor'@'%';
-- 授予列级权限(只能查询id和name列)
GRANT SELECT(id, name) ON company_db.users TO 'limited'@'localhost';
-- 授予存储过程执行权限
GRANT EXECUTE ON PROCEDURE company_db.calc_bonus TO 'app_user'@'%';
-- 授予创建视图权限
GRANT CREATE VIEW, SHOW VIEW ON company_db.* TO 'developer'@'localhost';
-- 授予资源限制(每小时最多100次查询)
GRANT SELECT ON *.* TO 'reporter'@'%'
WITH MAX_QUERIES_PER_HOUR 100;
2.3 撤销权限(REVOKE)
语法:
sql
REVOKE 权限列表 ON 权限级别 FROM '用户名'@'主机名';
-- 撤销 WITH GRANT OPTION 权限(特殊)
REVOKE GRANT OPTION FOR 权限列表 ON 权限级别 FROM '用户名'@'主机名';
-- 撤销所有权限(不删除用户)
REVOKE ALL PRIVILEGES, GRANT OPTION FROM '用户名'@'主机名';
示例:
sql
-- 撤销特定权限
REVOKE INSERT, UPDATE ON company_db.* FROM 'app_user'@'%';
-- 撤销全局权限
REVOKE ALL PRIVILEGES ON *.* FROM 'admin'@'localhost';
-- 撤销列级权限(MySQL不支持直接撤销列权限,需重新赋予完整权限再限制列)
-- 通常的做法是先删除列权限的GRANT,然后重新赋予更窄的权限
2.4 查看权限
sql
-- 查看当前用户的权限
SHOW GRANTS;
SHOW GRANTS FOR CURRENT_USER;
-- 查看指定用户的权限
SHOW GRANTS FOR '用户名'@'主机名';
-- 更详细的权限信息(通过表查询)
SELECT * FROM mysql.user WHERE user='用户名'\G
SELECT * FROM mysql.db WHERE user='用户名'\G
SELECT * FROM mysql.tables_priv WHERE user='用户名'\G
SELECT * FROM mysql.columns_priv WHERE user='用户名'\G
示例:
sql
SHOW GRANTS FOR 'john'@'localhost';
2.5 刷新权限
修改了 mysql.user 或其他权限表后,需执行以下命令使更改生效:
sql
FLUSH PRIVILEGES;
通常在使用 GRANT 和 REVOKE 命令时,MySQL 会自动刷新,但直接操作权限表(INSERT/UPDATE/DELETE)后必须手动执行 FLUSH PRIVILEGES。
三、角色管理(MySQL 8.0+)
角色是权限的集合,可以方便地批量管理用户权限。
3.1 创建角色
sql
CREATE ROLE [IF NOT EXISTS] '角色名'[@'主机名'];
示例:
sql
CREATE ROLE 'app_read';
CREATE ROLE 'app_write';
CREATE ROLE 'db_admin'@'localhost';
3.2 删除角色
sql
DROP ROLE [IF EXISTS] '角色名'[@'主机名'];
示例:
sql
DROP ROLE 'app_read';
3.3 授予权限给角色
sql
GRANT SELECT ON company_db.* TO 'app_read';
GRANT INSERT, UPDATE, DELETE ON company_db.* TO 'app_write';
3.4 将角色授予用户
sql
GRANT '角色名'[@'主机名'] TO '用户名'@'主机名';
示例:
sql
GRANT 'app_read' TO 'reporter'@'localhost';
GRANT 'app_write' TO 'editor'@'%';
3.5 激活角色
用户登录后默认角色可能未激活。默认情况下,在 MySQL 8.0 中,如果设置了 activate_all_roles_on_login 为 ON,则自动激活所有授予的角色;否则需要手动激活或设置默认角色。
查看当前激活的角色:
sql
SELECT CURRENT_ROLE();
设置用户的默认角色(自动激活):
sql
SET DEFAULT ROLE '角色名' TO '用户名'@'主机名';
-- 示例
SET DEFAULT ROLE 'app_read' TO 'reporter'@'localhost';
-- 设置所有授予的角色为默认角色
SET DEFAULT ROLE ALL TO 'user'@'host';
会话中手动激活角色:
sql
SET ROLE '角色名';
SET ROLE ALL; -- 激活所有授予的角色
SET ROLE NONE; -- 无角色
SET ROLE DEFAULT; -- 激活默认角色
3.6 撤销用户的角色
sql
REVOKE '角色名' FROM '用户名'@'主机名';
示例:
sql
REVOKE 'app_read' FROM 'reporter'@'localhost';
3.7 查看角色信息
sql
-- 查看所有角色
SELECT * FROM mysql.user WHERE account_locked='Y' AND password_expired='Y';
-- 查看角色拥有的权限
SHOW GRANTS FOR '角色名';
-- 查看用户拥有的角色
SELECT * FROM mysql.role_edges WHERE TO_USER='用户名';
-- 查看当前会话的角色
SELECT CURRENT_ROLE();
四、资源限制管理
资源限制用于防止单个用户过度消耗数据库资源。
4.1 设置资源限制
可在 GRANT 或 ALTER USER 中设置:
sql
-- 在 GRANT 中设置
GRANT SELECT ON *.* TO 'webuser'@'%'
WITH MAX_QUERIES_PER_HOUR 500
MAX_UPDATES_PER_HOUR 200
MAX_CONNECTIONS_PER_HOUR 50
MAX_USER_CONNECTIONS 10;
-- 使用 ALTER USER 修改现有用户(MySQL 8.0+)
ALTER USER 'webuser'@'%'
WITH MAX_QUERIES_PER_HOUR 1000
MAX_UPDATES_PER_HOUR 500;
参数说明:
MAX_QUERIES_PER_HOUR:每小时允许的查询次数MAX_UPDATES_PER_HOUR:每小时允许的更新次数MAX_CONNECTIONS_PER_HOUR:每小时允许的连接次数MAX_USER_CONNECTIONS:同一时刻允许的最大连接数
4.2 查看资源限制
sql
SELECT user, host, max_questions, max_updates, max_connections, max_user_connections
FROM mysql.user WHERE user='webuser';
4.3 清除资源计数器
sql
FLUSH USER_RESOURCES;
五、认证插件管理
MySQL 8.0 默认使用 caching_sha2_password,而 5.7 默认是 mysql_native_password。
5.1 更改认证插件
sql
-- 修改用户使用 mysql_native_password(兼容旧版客户端)
ALTER USER 'user'@'host' IDENTIFIED WITH mysql_native_password BY 'password';
-- 修改为 caching_sha2_password(MySQL 8.0 默认)
ALTER USER 'user'@'host' IDENTIFIED WITH caching_sha2_password BY 'password';
-- 不指定密码,仅改变插件(密码保持不变)
ALTER USER 'user'@'host' IDENTIFIED WITH mysql_native_password;
5.2 查看认证插件
sql
SELECT user, host, plugin FROM mysql.user;
六、代理用户管理
代理用户允许一个用户以另一个用户的权限执行操作。
6.1 授予代理权限
sql
GRANT PROXY ON '被代理用户'@'主机' TO '代理用户'@'主机';
示例:
sql
CREATE USER 'app_proxy'@'localhost' IDENTIFIED BY 'proxy';
CREATE USER 'app_backend'@'localhost' IDENTIFIED BY 'backend';
-- 允许 app_proxy 代理 app_backend
GRANT PROXY ON 'app_backend'@'localhost' TO 'app_proxy'@'localhost';
6.2 查看代理信息
sql
SELECT * FROM mysql.proxies_priv;
6.3 撤销代理权限
sql
REVOKE PROXY ON 'app_backend'@'localhost' FROM 'app_proxy'@'localhost';
七、密码管理高级功能(MySQL 8.0+)
7.1 密码重用策略
sql
-- 设置密码不能与最近5次使用的密码相同
ALTER USER 'user'@'host' PASSWORD HISTORY 5;
-- 设置密码不能与过去90天内使用的密码相同
ALTER USER 'user'@'host' PASSWORD REUSE INTERVAL 90 DAY;
-- 同时设置
ALTER USER 'user'@'host'
PASSWORD HISTORY 5
PASSWORD REUSE INTERVAL 90 DAY;
7.2 密码强度验证(需安装 validate_password 组件)
sql
-- 安装插件(如果未安装)
INSTALL COMPONENT 'file://component_validate_password';
-- 设置密码策略
SET GLOBAL validate_password.policy = 'STRONG';
SET GLOBAL validate_password.length = 12;
7.3 双密码(Dual Password)
sql
-- 设置主密码和次密码(用于轮换)
ALTER USER 'user'@'host' IDENTIFIED BY 'new_password' RETAIN CURRENT PASSWORD;
-- 弃用旧密码
ALTER USER 'user'@'host' DISCARD OLD PASSWORD;
八、安全相关操作
8.1 忘记 root 密码重置(命令行)
bash
# 停止 MySQL 服务
sudo systemctl stop mysql
# 跳过授权表启动
sudo mysqld_safe --skip-grant-tables &
# 登录(无需密码)
mysql -u root
# 在 MySQL 中清空 root 密码
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY '';
# 正常重启 MySQL
sudo systemctl restart mysql
# 使用新密码登录后设置密码
mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
8.2 限制用户登录来源
sql
-- 创建只能从特定IP登录的用户
CREATE USER 'user'@'192.168.1.100' IDENTIFIED BY 'pass';
-- 创建只能从内网域名登录的用户
CREATE USER 'user'@'internal.example.com' IDENTIFIED BY 'pass';
8.3 查看当前登录会话
sql
SHOW PROCESSLIST;
SELECT * FROM information_schema.processlist;
8.4 终止用户会话
sql
-- 首先找到连接ID
SHOW PROCESSLIST;
-- 然后杀死指定连接
KILL CONNECTION 123; -- 礼貌关闭
KILL QUERY 123; -- 仅杀死当前查询,不关闭连接
九、综合示例
示例1:创建应用程序用户并授权
sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS ecommerce;
-- 创建只读角色
CREATE ROLE 'readonly';
GRANT SELECT ON ecommerce.* TO 'readonly';
-- 创建读写角色
CREATE ROLE 'readwrite';
GRANT SELECT, INSERT, UPDATE, DELETE ON ecommerce.* TO 'readwrite';
-- 创建用户
CREATE USER 'app_user'@'%' IDENTIFIED BY 'SecurePass123';
CREATE USER 'report_user'@'localhost' IDENTIFIED BY 'ReportPass456';
-- 授予角色
GRANT 'readwrite' TO 'app_user'@'%';
GRANT 'readonly' TO 'report_user'@'localhost';
-- 设置默认角色
SET DEFAULT ROLE 'readwrite' TO 'app_user'@'%';
SET DEFAULT ROLE 'readonly' TO 'report_user'@'localhost';
-- 查看权限
SHOW GRANTS FOR 'app_user'@'%';
示例2:细粒度权限控制
sql
-- 用户只能查询 orders 表中的 user_id 和 status 列
GRANT SELECT(user_id, status) ON ecommerce.orders TO 'support'@'localhost';
-- 用户只能插入 logs 表,不能更新或删除
GRANT INSERT ON ecommerce.logs TO 'audit'@'%';
-- 用户只能执行特定的存储过程
GRANT EXECUTE ON PROCEDURE ecommerce.sp_update_inventory TO 'inventory'@'localhost';
示例3:临时用户管理
sql
-- 创建临时账户,30天后密码过期,账户锁定
CREATE USER 'temp'@'localhost' IDENTIFIED BY 'tempPass'
PASSWORD EXPIRE INTERVAL 30 DAY
ACCOUNT LOCK;
-- 激活账户
ALTER USER 'temp'@'localhost' ACCOUNT UNLOCK;
-- 使用完成后立即锁定
ALTER USER 'temp'@'localhost' ACCOUNT LOCK;
-- 最终删除
DROP USER 'temp'@'localhost';
十、常用查询与维护
10.1 检查弱密码用户
sql
SELECT user, host, password_last_changed
FROM mysql.user
WHERE password_last_changed < NOW() - INTERVAL 180 DAY;
10.2 查看所有用户的全局权限
sql
SELECT user, host, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv
FROM mysql.user;
10.3 生成批量用户创建语句
sql
SELECT CONCAT("CREATE USER '", user, "'@'", host, "' IDENTIFIED BY 'randomPass';")
FROM (SELECT DISTINCT 'test_user' AS user, '%' AS host) AS t;
10.4 备份权限
sql
-- 使用 pt-show-grants 工具(Percona Toolkit)
pt-show-grants --user=root --password=root > grants_backup.sql
-- 或手动生成 GRANT 语句
SELECT CONCAT("SHOW GRANTS FOR '", user, "'@'", host, "';") FROM mysql.user;
十一、注意事项与最佳实践
| 方面 | 建议 |
|---|---|
| 密码安全 | 使用强密码(>12位,混合字符),定期更换;避免明文存储密码。 |
| 最小权限原则 | 只授予用户完成任务所需的最小权限,避免滥用 ALL PRIVILEGES。 |
| 主机限制 | 生产环境避免使用 '%' 通配符,限制到具体IP或网段。 |
| 角色管理 | MySQL 8.0 以上建议使用角色简化权限管理。 |
| 审计 | 定期审查用户权限,移除不再需要的账号。 |
| 备份 | 定期使用 pt-show-grants 或备份 mysql 系统库。 |
| 连接加密 | 要求使用 SSL 连接(REQUIRE SSL 在 CREATE USER 或 GRANT 中)。 |
| 密码历史 | 开启密码重用限制,防止重复使用旧密码。 |
以上完整涵盖了 MySQL 中用户与权限管理的所有 DCL 操作命令,包括用户管理、权限授予/撤销、角色管理、资源限制、认证插件、代理用户、密码高级功能等。根据实际安全需求选择适当命令即可。