mysql只读账号必须显式授予select权限且不授任何写权限,禁用写权限不可靠;需分步创建用户、精确限定主机、逐库授权、检查残留权限并验证。

只读权限必须用 GRANT SELECT 显式授予,不能靠禁用写权限来“补漏”
MySQL 没有“只读用户”这种内置类型,所谓只读,本质是只给 SELECT、不给 INSERT/UPDATE/DELETE/DROP 等任何写权限。靠 REVOKE 去删掉已有权限极不可靠——容易漏掉 TRUNCATE、LOCK TABLES 或 CREATE VIEW 这类隐性写能力。最干净的做法是:从零开始,只执行 GRANT SELECT。
常见错误现象:
- 用户能执行
SELECT,但SHOW CREATE TABLE报错:缺INFORMATION_SCHEMA权限 - 用户登录失败,报
ERROR 1045 (28000):漏了USAGE权限(GRANT SELECT不自动带连接权) - 用户能查到
mysql库或其它业务库:误授了*.*或没清理旧账号
CREATE USER 和 GRANT 必须分两步,且主机名要精确限定
MySQL 5.7+ 不支持在 CREATE USER 语句里直接带 GRANT,合写会报 ERROR 1064。同时,主机名别用 '%' 放行所有 IP,生产环境应缩到最小网段,比如 '192.168.10.%'。
实操建议:
- 先创建用户:
CREATE USER 'reporter'@'192.168.10.%' IDENTIFIED WITH mysql_native_password BY 'StrongPass_2026!'; - 再授只读权:
GRANT SELECT ON `sales_db`.* TO 'reporter'@'192.168.10.%';(库名加反引号,防横线或关键字冲突) - 如需查表结构,补一句:
GRANT SELECT ON INFORMATION_SCHEMA.* TO 'reporter'@'192.168.10.%'; - 不要执行
GRANT SELECT ON *.*——它会暴露mysql、performance_schema等系统库
多个库只读?逐个 GRANT SELECT ON db_name.*,别偷懒
MySQL 不支持一条语句批量授权多个库,GRANT SELECT ON `db1`.*, `db2`.* 是语法错误。必须对每个库单独执行 GRANT。这点容易被忽略,尤其当 DBA 用脚本批量生成时,一不小心就漏掉某个库。
典型场景:
- 报表用户需读
sales_db和reports_db:执行两条独立语句 - 跨库 JOIN 查询失败?确认两个库都已授权,且用户 host 部分完全一致(
'reporter'@'192.168.10.%'不能和'reporter'@'localhost'混用) - 新库上线后只读权限不生效?MySQL 8.0 的角色不会自动继承新库权限,必须手动补
GRANT
验证权限前,先检查是否残留旧权限或全局权限
最常被跳过的一步:用 SHOW GRANTS FOR 'reporter'@'192.168.10.%'; 查当前实际权限。如果返回里出现 GRANT OPTION、SUPER、PROCESS 或任何非 USAGE+SELECT 的条目,说明账号不干净,应直接 DROP USER 重建。
关键细节:
-
FLUSH PRIVILEGES在绝大多数情况下不需要——GRANT自动刷新缓存;只有你手动改过mysql.user表才需要它 - 测试时用真实客户端连,别只在本地
mysql -u reporter -p测试,要模拟应用的真实连接源 IP -
SELECT ... FOR UPDATE会失败,这不是权限配置问题,而是该语句本身触发锁机制,需额外LOCK TABLES权限——只读用户不该用它
权限配置真正的复杂点不在语法,而在于“干净”二字:干净的账号、干净的主机范围、干净的授权路径。哪怕只漏一个 REVOKE INSERT ON mysql.*,都可能让只读账号变成信息泄露入口。











