只读用户本质是仅授select权限且显式撤销所有写权限的账号,而非禁用写操作;必须分步create user和grant,注意认证插件兼容性,额外授权information_schema必要表,并通过新连接验证select成功、insert和for update均报错。

只读用户不是“禁写”,而是“只给SELECT”
MySQL 没有 READ ONLY USER 这种账户类型,所谓只读,就是显式授予 SELECT 权限,且不授予任何写权限(INSERT、UPDATE、DELETE、DROP、ALTER 等)。关键点在于:权限是叠加的,GRANT SELECT 不会自动撤销已有写权限。如果目标用户已存在,直接 GRANT SELECT 很可能无效。
实操建议:
- 先查清当前权限:
SHOW GRANTS FOR 'dev_ro'@'192.168.5.%'; - 若输出中含
INSERT或ALL PRIVILEGES,必须先REVOKE再授,不能只加不减 - 更稳妥的做法是删掉重建:
DROP USER 'dev_ro'@'192.168.5.%';,再从零创建
CREATE USER 和 GRANT 必须分两步,且注意认证插件
MySQL 8.0 默认用 caching_sha2_password 插件,但很多开发工具(如旧版 DBeaver、某些 Python mysqlclient)不兼容,连不上时提示 authentication plugin 'caching_sha2_password' cannot be loaded——这不是权限问题,是握手失败。
实操建议:
- 创建用户时显式指定兼容插件:
CREATE USER 'dev_ro'@'192.168.5.%' IDENTIFIED WITH mysql_native_password BY 'DevRoPass2026!'; - 立刻授权(不能合并在一条语句里):
GRANT SELECT ON `app_dev`.* TO 'dev_ro'@'192.168.5.%'; - 如需查多个库,逐个授权:
GRANT SELECT ON `logging_db`.* TO 'dev_ro'@'192.168.5.%';,别用*.* -
FLUSH PRIVILEGES;在绝大多数情况下非必需;只有手动改过mysql.user表才需要它
开发场景下必须额外处理 INFORMATION_SCHEMA
开发人员常用 SHOW CREATE TABLE、DESCRIBE t1 或 ORM 自动执行 SELECT * FROM information_schema.COLUMNS,这些操作依赖 information_schema 的只读访问。但默认情况下,GRANT SELECT ON app_dev.* 不包含它,结果是查询报错:ERROR 1142 (42000): SELECT command denied。
实操建议:
- 最小化授权:
GRANT SELECT (TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT) ON `information_schema`.`COLUMNS` TO 'dev_ro'@'192.168.5.%'; - 或更常用但略宽泛的方式:
GRANT SELECT ON `information_schema`.`TABLES` TO 'dev_ro'@'192.168.5.%'; - 不要授整个
information_schema库,尤其避免SCHEMATA或STATISTICS表,可能暴露库名、索引结构等敏感信息
验证时最容易漏掉的三个动作
只看 SHOW GRANTS 输出全是 SELECT 不代表真安全。开发环境常因测试不全,上线后才发现 ORM 报错或字段查不到。
实操建议,用新连接登录后立刻执行:
-
SELECT USER(), CURRENT_USER();——确认匹配的是你刚建的账号(CURRENT_USER()显示实际生效账号,USER()是你声明的连接身份) -
SELECT COUNT(*) FROM app_dev.users JOIN app_dev.orders USING(user_id);——验证跨表关联是否可查(否则说明少授了某个表的SELECT) -
INSERT INTO app_dev.users(name) VALUES('test');和SELECT * FROM app_dev.users FOR UPDATE;——前者必须报ERROR 1142,后者也必须报错(FOR UPDATE需锁表权限,只读用户不该有)
真正麻烦的点不在授权语句本身,而在于开发工具的行为不可见:比如某次 mysqldump --no-create-info 会尝试读 performance_schema,或者 VS Code MySQL 扩展自动执行 SELECT @@sql_mode ——这些都和权限无关,但会让开发者误以为账号配置失败。











