MySQL无命名空间但以database实现逻辑隔离,权限分账户层与业务层双轨控制,通过user@host细粒度管控访问。

MySQL里没有“命名空间”概念,但有等效的数据库(database)隔离机制
MySQL 不支持像编程语言那样的命名空间(namespace),它的逻辑隔离单位是 database。每个 database 是独立的表集合容器,不同 database 下可以存在同名表而互不干扰——这本质上就是命名空间要解决的问题。
常见误区是以为建个 schema 就等于有了命名空间,其实 CREATE SCHEMA 只是 CREATE DATABASE 的同义词,不引入额外抽象层。真正要注意的是:
-
database名必须全局唯一,不能重复;跨库查询需显式写成db_name.table_name - 用户对某个
database的权限默认不自动延伸到新创建的同名库(哪怕删了重建) - 用
mysqldump --databases备份时,若漏掉--databases参数,会丢失CREATE DATABASE语句,导致恢复后无库结构
权限控制分两层:MySQL账户权限 vs 业务角色权限,别混在一起
很多人一上来就在 users 表里加 is_admin 字段,结果权限改一次就得改代码、发版、重启服务——这是把应用层 RBAC 塞进了数据库账户体系,违背分层原则。
正确的做法是双轨并行:
-
MySQL 账户权限:只管“能不能连、能看哪些库”,用
GRANT SELECT ON app_db.* TO 'app_user'@'10.0.2.%'这类语句配置,最小化授予(比如生产环境绝不给DROP或ALTER) -
业务角色权限:用
users、roles、permissions、user_roles、role_permissions五张表实现,登录后查 JOIN 结果缓存到 session,校验逻辑全在应用层
混淆两者的典型后果:开发用 root 连库调试,上线后忘了切账号,导致任意 SQL 都能执行;或者给测试用户开了 mysql.user 表读权限,结果暴露所有账号密码哈希。
多用户隔离不是靠“一个用户一个库”,而是靠 host + privilege 组合控制
看到“多用户隔离”,第一反应建一堆 database 并分配不同用户?太重了。实际更轻量、更安全的做法是利用 MySQL 的 user@host 二元标识和细粒度权限。
例如,让前端服务、数据分析组、DBA 同时访问同一个 sales_db,但权限完全不同:
-
web_app@'10.0.1.%':只允许SELECT, INSERT, UPDATEonsales_db.orders,禁止DELETE -
analyst@'10.0.2.%':允许SELECTonsales_db.*,但禁止访问sales_db.users表 -
dba@'127.0.0.1':仅限本地登录,拥有ALL PRIVILEGESonsales_db,且密码强制 90 天过期
这种方案避免了库级冗余,也防止误操作波及其它环境;关键点在于:主机地址(host)不是可有可无的字段,它是权限生效的前提条件,'user'@'%' 和 'user'@'localhost' 是两个完全独立的账户。
权限变更后不生效?先检查 flush privileges 和连接复用问题
执行完 GRANT 或 REVOKE 后,立刻用新用户连不上?不是语法错,大概率是这两件事没做:
- MySQL 5.7+ 默认不需要
FLUSH PRIVILEGES,但如果你手动改过mysql.user表(比如用UPDATE直接更新密码字段),就必须执行它,否则权限缓存不会刷新 - 应用使用连接池(如 HikariCP、PooledConnection)时,旧连接仍持有原权限上下文,新权限只对新建连接生效;需重启应用或等待连接自动回收(取决于 idle timeout 设置)
- 注意
SHOW GRANTS FOR 'user'@'host'查的是当前生效权限,但SELECT * FROM mysql.user显示的是磁盘存储值,二者可能因未 flush 而不一致
最容易被忽略的是:权限判断发生在连接建立阶段,而不是 SQL 执行时。所以即使你 GRANT 成功了,正在运行的长连接依然按老权限跑,直到断开重连。










