在MySQL运维中,为开发人员或数据分析师开通数据库访问时,最安全的做法不是给全部权限,而是创建只能查询的只读账号。MySQL的权限体系以授权表为基础,通过GRANT语句分配操作许可,用REVOKE语句撤销许可。下面直接演示完整配置过程。

一、创建只读账号并授予SELECT权限
首先使用root或具备CREATE USER及GRANT权限的账号登录MySQL,创建新用户。MySQL 8.0之后默认使用caching_sha2_password插件,密码以明文写在语句中会被自动加密存储。我们创建一个名为reader的用户,只允许从本地连接。
创建用户后,使用GRANT SELECT授予其对指定库的读取权限。SELECT权限意味着该用户能执行SELECT语句、SHOW TABLES以及查看表结构,但不能修改任何数据。如果需要更细粒度控制,可以只授权某几张表。
-- 创建只读用户,密码为Read@1234 CREATE USER 'reader'@'localhost' IDENTIFIED BY 'Read@1234'; -- 授予test库下所有表的SELECT权限 GRANT SELECT ON test.* TO 'reader'@'localhost'; -- 刷新权限使配置生效 FLUSH PRIVILEGES;
上述命令中,test.* 表示test库的全部表。如果只想开放user表,可写成 GRANT SELECT ON test.user TO 'reader'@'localhost';。授权后该用户尝试执行INSERT会收到ERROR 1142的拒绝提示,从底层杜绝了写操作风险。
除了单库授权,也可以授予全局只读权限,但生产环境极不推荐。全局SELECT能让用户读取所有库包括mysql系统库,可能泄露用户凭证信息。坚持最小权限原则,仅开放必要库表。
二、验证只读账号的权限范围
权限授予完成后,必须实际登录验证,确认账号确实只有查询能力。退出root,使用reader账号连接,执行查询与写操作对比。
下面的示例展示了在reader会话中查询成功、插入被拒的现象。MySQL返回的错误码明确说明缺失INSERT权限,证明只读限制已生效。
-- 使用reader登录后执行
SELECT * FROM test.user LIMIT 1; -- 成功返回数据
INSERT INTO test.user(name) VALUES('tom'); -- 报错
-- ERROR 1142 (42000): INSERT command denied to user 'reader'@'localhost' for table 'user'
也可通过系统表查看授权结果。查询mysql.user与mysql.db能确认用户是否存在、是否具有写权限字段为N。在mysql.db表中,用户对应的Select_priv为Y,而Insert_priv、Update_priv均为N,说明权限模型正确。
验证环节常被忽略,但它是安全配置的必要闭环。很多事故源于以为授权成功,实际因未FLUSH PRIVILEGES或连接 host 不匹配导致权限未加载。
三、使用REVOKE回收权限
当员工转岗、离职或项目结束,应及时回收账号权限。REVOKE语法与GRANT对应,指定要撤销的权限、库表及用户。注意REVOKE只收回权限,不删除账号,账号可保留以备审计或 reuse。
若之前授予了test.*的SELECT,回收时也必须用相同的粒度,否则可能提示无对应权限记录。回收后再次执行查询会失败,表明权限已被注销。
-- 回收reader在test库的所有SELECT权限 REVOKE SELECT ON test.* FROM 'reader'@'localhost'; FLUSH PRIVILEGES; -- 验证:以下语句将报错 SELECT * FROM test.user; -- ERROR 1142 (42000): SELECT command denied to user 'reader'@'localhost' for table 'user'
如果需要彻底删除账号,可在REVOKE后执行 DROP USER 'reader'@'localhost';。但在合规要求严格的环境,通常保留账号并置为无权限,以便追踪历史操作记录。
REVOKE也支持回收全部权限,命令为 REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'reader'@'localhost';。该写法会清空用户所有授权,但同样不影响账号本身存在状态。
四、常见误区与注意事项
一个常见误区是认为GRANT SELECT ON *.* 比逐库授权更省事。实际上这会让用户能看到系统库,且后续REVOKE需对应全局层级,管理混乱。应按业务库逐一授权。
另一个坑是host部分。'reader'@'localhost' 与 'reader'@'%' 在MySQL中是不同账号,权限互不影响。若用户从远程连接却只建了本地账号,会报访问拒绝。规划时需明确接入来源。
| 操作 | 语句示例 | 影响 |
|---|---|---|
| 建用户 | CREATE USER 'u'@'localhost' IDENTIFIED BY 'p'; | 新增账号无权限 |
| 授只读 | GRANT SELECT ON db.* TO 'u'@'localhost'; | 仅可查询 |
| 收权限 | REVOKE SELECT ON db.* FROM 'u'@'localhost'; | 查询也被禁 |
| 删账号 | DROP USER 'u'@'localhost'; | 账号消失 |
最后提醒,任何权限变更后都应执行FLUSH PRIVILEGES,除非使用的是MySQL 8.0以上且通过ACL语句自动同步的机制。但在混合版本环境中,显式刷新是最稳妥的习惯。
通过GRANT SELECT与REVOKE的配合,可以用极低成本实现数据库只读共享与权限生命周期管理,既满足协作需要,又守住数据不被篡改的底线。
MySQLGRANT_SELECTREVOKE修改时间:2026-08-06 22:39:15