MySQL权限是白名单机制,必须显式授予GRANT SELECT ON mydb.才实现真正只读;GRANT SELECT ON .*会暴露系统库结构,存在信息泄露风险。
MySQL 权限是白名单机制:只授 GRANT SELECT ON mydb.* 才算真正只读;GRANT SELECT ON *.* 会暴露 mysql、performance_schema 等系统库结构,存在信息泄露风险。常见错误包括:
'my-db'.* → 语法错误,正确写法是 `my-db`.* 或无特殊字符时直接写 mydb.*
SELECT * FROM db1.t1 JOIN db2.t2 要求对 db1.* 和 db2.* 都显式执行 GRANT SELECT
REVOKE INSERT 等操作能“加固”只读 → 实际上没授过的权限无需回收,反而容易漏掉 TRUNCATE、LOCK TABLES 等隐式写权限GRANT SELECT 只管“能做什么”,不管“能不能登录”。没有 USAGE,认证通过后立刻断连,报错 ERROR 1045 (28000): Access denied,哪怕密码完全正确。MySQL 8.0+ 不再自动附带 USAGE,这步不能跳。
GRANT USAGE ON *.* TO 'ro_user'@'192.168.10.%'
USAGE 是纯连接权,不带任何操作能力,必须和 SELECT 分开授予'%' 放行所有 IP,生产环境建议限定内网段,如 '192.168.10.%'
很多 ORM、监控工具或 DBA 手动查表结构时会执行 SHOW CREATE TABLE t1,这条语句底层依赖对 information_schema.TABLES 和 information_schema.COLUMNS 的 SELECT 权限。MySQL 5.7 默认允许访问,但 8.0+ 默认收紧。
SHOW CREATE TABLE 就会报 ERROR 1142 (42000): SELECT command denied
GRANT SELECT ON INFORMATION_SCHEMA.* TO 'ro_user'@'192.168.10.%'
performance_schema 或 sys,除非明确需要其视图MySQL 5.7 及以后不支持在 CREATE USER 时直接带 GRANT,强行写成一句会报错:ERROR 1064 (42000): You have an error in your SQL syntax。
CREATE USER 'ro_user'@'192.168.10.%' IDENTIFIED BY 'strong-pass-2024';,再 GRANT SELECT ON myapp_db.* TO 'ro_user'@'192.168.10.%';
GRANT 后无需 FLUSH PRIVILEGES(除非你手动改过 mysql.user 表),GRANT 自动刷新权限缓存最易被忽略的是:只读账号能执行 SELECT ... FOR UPDATE 吗?不能——它会触发锁机制,需 SELECT + LOCK TABLES 权限,而只读账号没后者,直接报 ERROR 1142。但这不代表绝对安全:如果用户有 EXECUTE 权限或能访问 SQL SECURITY DEFINER 视图,仍可能间接触发写行为。