必须显式授予select权限并补usage确保登录,禁用lock tables等隐式写权限,mysql 8.0+需显式授权information_schema.tables且设default role激活。

只读权限不是“不给写权限就自动生效”,而是必须显式授予 SELECT,并确保不混入任何隐式写权限(如 LOCK TABLES、SUPER)或系统库暴露风险。
CREATE USER 和 GRANT 必须分两步执行(MySQL 8.0+ 强制要求)
MySQL 8.0 不再支持在一条语句中创建用户并授予权限。常见错误是写成 GRANT SELECT ON db.* TO 'ro'@'%' IDENTIFIED BY 'pwd',这会直接报错 ERROR 1064 (42000)。
- 先创建用户(推荐指定认证插件,避免连接失败):
CREATE USER 'ro_app'@'192.168.10.%' IDENTIFIED WITH mysql_native_password BY 'StrongPass!2026';
- 再单独授权:
GRANT SELECT ON `app_db`.* TO 'ro_app'@'192.168.10.%';
- 若需跨库只读(如还要查
log_db),必须逐条执行:GRANT SELECT ON `log_db`.* TO 'ro_app'@'192.168.10.%';
别忘了 USAGE 权限:否则用户根本连不上
很多人只授 SELECT,结果用新用户登录时直接报 ERROR 1045 (28000): Access denied——不是密码错,是缺了连接权。MySQL 8.0+ 不再自动附带 USAGE,必须显式补上:
GRANT USAGE ON *.* TO 'ro_app'@'192.168.10.%';
-
USAGE是空权限占位符,只管认证通过后是否允许保持连接,不赋予任何操作能力 - 它和
SELECT必须共存,顺序无关
SHOW CREATE TABLE 失败?大概率缺 information_schema 显式授权
很多 ORM、监控工具或 DBA 手动查表结构时会执行 SHOW CREATE TABLE t1,但 MySQL 8.0+ 默认收紧对 information_schema 的访问。只授业务库权限会导致该命令报 ERROR 1142 (42000): SELECT command denied。
- 补授权即可(仅限 8.0+):
GRANT SELECT ON `information_schema`.`TABLES` TO 'ro_app'@'192.168.10.%';
- 如果还用
SHOW COLUMNS或查字段注释,可能还需:GRANT SELECT ON `information_schema`.`COLUMNS` TO 'ro_app'@'192.168.10.%';
- 不要用
GRANT SELECT ON information_schema.*——范围过大,且部分表(如PROCESSLIST)需要额外权限
REVOKE 不是可选项,而是防绕过关键动作
即使你没主动授过写权限,旧账号、复制账户或通配符主机匹配(如 'ro_app'@'%' 和 'ro_app'@'192.168.10.%' 同时存在)可能导致权限叠加。更危险的是残留的 SUPER 权限——拥有它的人可以临时关闭 read_only 或修改 binlog 行为。
- 显式回收高危权限(务必执行):
REVOKE INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, LOCK TABLES, SUPER, REPLICATION CLIENT ON *.* FROM 'ro_app'@'192.168.10.%';
- 验证是否干净:
SHOW GRANTS FOR 'ro_app'@'192.168.10.%';
输出应只含SELECT和USAGE行 -
FLUSH PRIVILEGES在 8.0+ 非强制,但仍建议执行,尤其当权限表被直改过或版本混合部署时
最容易被忽略的点:权限生效依赖精确的主机名匹配、反引号包裹含特殊字符的库名(如 `my-db`)、以及 information_schema 的细粒度授权——漏掉任意一项,都可能让“只读”在实际使用中突然失效或报错。











