MySQL | MySQL 8.0 权限管理实践-精确赋予库、表只读等权限

引言

MySQL 8.0 在权限管理方面引入了多项改进,包括角色(Role)动态权限密码过期策略等特性,使权限管理更加灵活和安全。本文基于 MySQL 8.0 语法,结合实际场景,详细介绍如何为数据库、表赋予只读、读写等精确权限。

权限体系原理图

权限检查流程

继承关系

MySQL 8.0 核心变化

特性 MySQL 5.7 及以前 MySQL 8.0
创建用户 GRANT ... IDENTIFIED BY 必须先 CREATE USER
角色支持 不支持 支持 CREATE ROLE
密码管理 基础功能 支持过期、历史记录、重试限制
动态权限 固定权限集 可扩展(如 BINLOG_ADMIN
账户锁定 不支持 ACCOUNT LOCK/UNLOCK
认证插件 mysql_native_password 默认 caching_sha2_password 默认

核心权限类型(MySQL 8.0)

权限 说明 适用场景
SELECT 读取数据 只读用户
INSERT 插入数据 数据录入
UPDATE 更新数据 数据修改
DELETE 删除数据 数据清理
CREATE 创建表/库 开发环境
DROP 删除表/库 管理员
ALTER 修改表结构 DDL 变更
INDEX 创建/删除索引 性能优化
EXECUTE 执行存储过程 应用账号
CREATE ROLE 创建角色 权限管理员
ALL PRIVILEGES 所有权限(除 GRANT) 完全控制

语法基础(MySQL 8.0)

sql 复制代码
-- 创建用户(8.0 必须先创建)
CREATE USER 'username'@'host' 
IDENTIFIED BY 'password'
[PASSWORD EXPIRE [DEFAULT|NEVER|INTERVAL N DAY]]
[ACCOUNT LOCK | UNLOCK];

-- 授予权限
GRANT privilege_type [(column_list)] 
ON [object_type] privilege_level 
TO 'username'@'host' 
[WITH GRANT OPTION];

-- 回收权限
REVOKE privilege_type 
ON privilege_level 
FROM 'username'@'host';

-- 查看权限
SHOW GRANTS FOR 'username'@'host';

-- 角色操作(8.0 新增)
CREATE ROLE 'role_name';
GRANT 'role_name' TO 'username'@'host';
SET DEFAULT ROLE 'role_name' TO 'username'@'host';

-- 权限立即生效(8.0 无需 FLUSH PRIVILEGES,但仍建议执行)
FLUSH PRIVILEGES;

使用场景与命令

场景一:只读用户 - 查询任意表

需求 :为数据分析师 analyst 创建账号,只能查询 sales_db 数据库的所有表,不能做任何修改。

sql 复制代码
-- 创建用户(MySQL 8.0 语法)
CREATE USER 'analyst'@'192.168.1.%' 
IDENTIFIED BY 'ReadOnly@2024'
PASSWORD EXPIRE INTERVAL 90 DAY;

-- 授予数据库级只读权限
GRANT SELECT ON sales_db.* TO 'analyst'@'192.168.1.%';

-- 验证
SHOW GRANTS FOR 'analyst'@'192.168.1.%';

权限决策流程图:

场景二:使用角色(Role)管理权限组

需求:多个只读用户需要相同权限,使用角色统一管理。

sql 复制代码
-- 创建角色(MySQL 8.0 核心特性)
CREATE ROLE 'readonly_role', 'readwrite_role';

-- 为角色授予权限
GRANT SELECT ON sales_db.* TO 'readonly_role';
GRANT SELECT, INSERT, UPDATE, DELETE ON sales_db.* TO 'readwrite_role';

-- 创建用户并赋予角色
CREATE USER 'alice'@'%' IDENTIFIED BY 'Alice@2024';
CREATE USER 'bob'@'%' IDENTIFIED BY 'Bob@2024';

-- 分配角色
GRANT 'readonly_role' TO 'alice'@'%';
GRANT 'readwrite_role' TO 'bob'@'%';

-- 激活角色(默认激活或设置默认角色)
SET DEFAULT ROLE 'readonly_role' TO 'alice'@'%';
SET DEFAULT ROLE 'readwrite_role' TO 'bob'@'%';

-- 查看角色权限
SHOW GRANTS FOR 'alice'@'%' USING 'readonly_role';

角色管理架构图:

场景三:只读用户 - 限制只能查特定表

需求 :外包人员只能查询 sales_db.orderssales_db.products 两张表。

sql 复制代码
CREATE USER 'outsource'@'10.0.0.%' 
IDENTIFIED BY 'Out@2024'
PASSWORD EXPIRE DEFAULT
FAILED_LOGIN_ATTEMPTS 3
PASSWORD_LOCK_TIME 2;

-- 表级授权
GRANT SELECT ON sales_db.orders TO 'outsource'@'10.0.0.%';
GRANT SELECT ON sales_db.products TO 'outsource'@'10.0.0.%';

-- 撤销全局数据库的默认权限
REVOKE ALL PRIVILEGES ON sales_db.* FROM 'outsource'@'10.0.0.%';

场景四:读写用户 - 允许增删改查

需求 :测试人员 tester 需要 test_db 库的完整读写能力,但不能修改表结构。

sql 复制代码
CREATE USER 'tester'@'%' 
IDENTIFIED BY 'Test@2024'
WITH MAX_QUERIES_PER_HOUR 10000;

-- 授予数据操作权限(不含 DDL)
GRANT SELECT, INSERT, UPDATE, DELETE ON test_db.* TO 'tester'@'%';

-- 禁止 DDL 操作(通过不授权实现)
-- 如果用户尝试 ALTER TABLE,将收到 ERROR 1142

场景五:动态权限使用(MySQL 8.0 新增)

需求 :备份账号需要 LOCK TABLESSELECT 权限,但不需其他管理权限。

sql 复制代码
-- MySQL 8.0 动态权限示例
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'Backup@2024';

-- 只授予备份所需的最小权限集
GRANT SELECT, LOCK TABLES, SHOW VIEW ON mydb.* TO 'backup_user'@'localhost';

-- 对于二进制日志管理,使用动态权限(代替 SUPER)
GRANT BINLOG_ADMIN, REPLICATION_SLAVE_ADMIN ON *.* TO 'repl_user'@'%';

场景六:列级权限 + 视图替代方案

需求 :客服人员只能查询 users 表的 nameemail,不能查看敏感字段。

sql 复制代码
-- 方案一:直接列授权(不推荐,管理复杂)
GRANT SELECT (name, email) ON app_db.users TO 'support'@'%';

-- 方案二:创建视图(推荐)
CREATE VIEW app_db.v_users_public AS 
SELECT id, name, email, last_login_date 
FROM app_db.users;

GRANT SELECT ON app_db.v_users_public TO 'support'@'%';

场景七:账户锁定与密码管理

sql 复制代码
-- 创建时必须设置密码且过期
CREATE USER 'temp_user'@'%' 
IDENTIFIED BY 'Temp@2024'
PASSWORD EXPIRE;

-- 账户锁定(防止未授权使用)
ALTER USER 'temp_user'@'%' ACCOUNT LOCK;

-- 账户解锁
ALTER USER 'temp_user'@'%' ACCOUNT UNLOCK;

-- 强制密码历史(防止重复使用旧密码)
ALTER USER 'temp_user'@'%' PASSWORD HISTORY 5;

-- 限制错误登录尝试(MySQL 8.0.19+)
ALTER USER 'temp_user'@'%' 
FAILED_LOGIN_ATTEMPTS 3 
PASSWORD_LOCK_TIME UNBOUNDED;

权限分配决策树

最佳实践

使用角色管理权限组

sql 复制代码
-- 创建标准角色
CREATE ROLE 'app_readonly', 'app_readwrite', 'app_admin';

-- 赋予权限
GRANT SELECT ON app_db.* TO 'app_readonly';
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_readwrite';
GRANT ALL ON app_db.* TO 'app_admin';

-- 分配角色给用户
GRANT 'app_readonly' TO 'developer1'@'%';
GRANT 'app_readwrite' TO 'developer2'@'%';

最小权限原则示例

sql 复制代码
-- 创建只读账号的最佳实践
CREATE USER 'report_user'@'192.168.10.%' 
IDENTIFIED BY 'StrongP@ssw0rd!'
PASSWORD EXPIRE INTERVAL 180 DAY;

-- 只授予必要权限
GRANT SELECT ON reporting_db.* TO 'report_user'@'192.168.10.%';

-- 不授予任何其他权限
-- 没有 INSERT/UPDATE/DELETE/ALTER/CREATE/DROP

定期权限审计查询

sql 复制代码
-- 查看所有用户及其角色
SELECT user, host, account_locked, password_expired 
FROM mysql.user;

-- 查看特定用户的权限
SHOW GRANTS FOR 'username'@'host';

-- 查看所有角色
SELECT * FROM mysql.roles_mapping;

-- 查看哪些用户拥有特定数据库的权限
SELECT * FROM mysql.db WHERE db = 'sales_db';

常见问题排查

问题 可能原因 解决方案
授权后无权限 缓存未刷新 FLUSH PRIVILEGES
角色未生效 角色未激活 SET DEFAULT ROLE
密码认证失败 8.0 默认 caching_sha2_password 客户端更新驱动或使用 mysql_native_password
GRANT 报错 8.0 不允许 GRANT 创建用户 先用 CREATE USER
账号自动锁定 超过 FAILED_LOGIN_ATTEMPTS ALTER USER ... ACCOUNT UNLOCK
相关推荐
阿巴斯甜2 小时前
Map
android
巫山老妖2 小时前
鹅厂十年:三段式技术成长复盘
android·人工智能·程序员
阿巴斯甜2 小时前
List集合
android
筑梦之路2 小时前
harbor数据库报错权限异常如何处理——筑梦之路
数据库·harbor
ooseabiscuit3 小时前
Laravel6.x核心优化与特性全解析
android·开发语言·javascript
czlczl200209253 小时前
理解 MySQL 行锁:两阶段锁协议与热点更新优化
数据库·mysql
AllData公司负责人3 小时前
通过Postgresql同步到Doris,全视角演示AllData数据中台核心功能效果,涵盖:数据入湖仓,数据同步,数据处理,数据服务,BI可视化驾驶舱
java·大数据·数据库·数据仓库·人工智能·python·postgresql
哆啦A梦15883 小时前
20, Springboot3+vue3实现前台轮播图和详情页的设计
javascript·数据库·spring boot·mybatis·vue3
阿巴斯甜4 小时前
Kotlin 协程 Coroutine
android