schema级别隔离在mysql中完全可行,但需严格满足三要素:应用层绝对控制库名、连接池精准绑定database参数、建库操作经白名单校验;漏任一环即导致租户数据串访或越权。

Schema 级别隔离在 MySQL 中完全可行,但不是配完权限就一劳永逸的事——它依赖应用层对库名的绝对控制、连接池的精准绑定、以及 DDL 操作的严格白名单校验。漏掉任意一环,租户数据就可能互相可见甚至被篡改。
GRANT 语句必须写成 GRANT SELECT ON `tenant_x`.*
MySQL 的权限系统是“库表两级绑定”,GRANT SELECT ON tenant_x(没加 .*)只授予 USAGE 权限,连 SHOW TABLES 都会被拒绝;而漏掉反引号 ` 在租户名含数字或短横线(如 tenant-123)时直接报语法错误。
-
.*绝对不能省:否则权限不落地,应用执行SELECT * FROM users会报Access denied for user ... to database 'tenant_x' - 反引号
`必须包裹 schema_name:尤其当租户标识含短横线、数字开头或保留字风险时 - 禁止用
WITH GRANT OPTION:否则租户账号可自行授 CREATE DATABASE,直接越权建库 - 授权后立刻回收全局权限:
REVOKE ALL PRIVILEGES ON *.* FROM 'tenant_456'@'%',再FLUSH PRIVILEGES
连接池必须用 database=xxx 参数,而非 USE xxx
USE tenant_x 是会话级命令,连接复用时极易残留旧 Schema,导致后续请求查到其他租户的同名表;而 JDBC 连接串中显式指定 database=tenant_x(如 jdbc:mysql://localhost:3306/?database=tenant_456),能让驱动在建连时就绑定上下文,更可靠。
- Druid:设
connectionInitSqls=["USE tenant_456"]不够,必须配合initConnectionSqls+ 每次获取连接后校验database()返回值是否匹配 - HikariCP:无内置 init SQL 支持,需用
ConnectionCustomizer.onAcquire()执行USE tenant_x,且每次都要重置 - 旧版
mysql-connector-java的?database=xxx在重连时大概率丢失,现象是偶发串库 - 应用启动时必须主动调用
SELECT DATABASE()校验当前连接的 schema 是否与预期一致
创建租户 Schema 必须走白名单校验,不能拼接用户输入
DDL 语句不支持预编译参数,CREATE SCHEMA IF NOT EXISTS ? 会直接报错。所有租户标识(如 tenant_id)若未经校验就拼进建库语句,等于给 SQL 注入开后门。
- 只允许字符集:字母、数字、下划线,长度 3–32 位,正则为
^[a-zA-Z0-9_]{3,32}$ - 禁止敏感词:
mysql、information_schema、performance_schema、sys - 建库必须由专用 DDL 账号执行(如
ddl_admin),该账号不应拥有任何租户表级权限 - 安全示例:
CREATE SCHEMA IF NOT EXISTS `tenant_abcd1234` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
租户账号要禁用 SHOW DATABASES,但重点不在隐藏库名
SHOW DATABASES 默认列出所有库名,这是 MySQL 设计行为,不算漏洞。真正危险的是租户账号拥有 PROCESS、FILE、SUPER 等全局权限,或应用层把库名当变量拼进 SQL。
- 可选心理安慰操作:
REVOKE SHOW DATABASES ON *.* FROM 'tenant_456'@'%' - 关键动作是限制 host:
'tenant_456'@'10.20.30.%'比'%'少一个攻击面 - INFORMATION_SCHEMA.SCHEMATA 仍能查到库名,但无表结构和数据权限——只要权限和连接绑定到位,这不影响隔离性
- 最易被忽略的点:ORM 框架(如 Hibernate)自动 fallback 到默认库的行为,必须关闭或拦截
Schema 隔离真正的复杂点不在建库或授权,而在连接生命周期管理——连接池是否每次都能干净地绑定到目标 Schema,应用是否在任何路径下都未绕过校验逻辑,以及运维脚本执行跨租户聚合时,有没有误读 information_schema 中的非业务表。这些地方一旦松动,隔离就形同虚设。











