ETL账号必须禁用所有写权限和DDL权限,只授予精确到表的SELECT权限,显式回收information_schema和performance_schema读权限,禁止LOCK TABLES等物理操作权限。

ETL账号必须禁用所有写权限和DDL权限
ETL工具只负责把数据从MySQL拉出去,不需要任何修改能力。哪怕只漏掉一个DROP或ALTER,就可能被恶意SQL或配置错误触发误删表。真实事故里,不少ETL脚本因参数拼接漏洞执行了DROP TABLE mysql.user,根源就是权限没切干净。
- 绝对禁止授予
INSERT、UPDATE、DELETE、DROP、CREATE、ALTER、GRANT OPTION - 即使ETL用到临时表,也应由DBA预建好,ETL账号只读;不要给
CREATE TEMPORARY TABLES - 用
REVOKE INSERT, UPDATE, DELETE, DROP, CREATE, ALTER ON *.* FROM 'etl_user'@'10.10.20.%';显式回收,别依赖“没授过就安全”
SELECT权限必须精确到表,不能用app_db.*
ETL抽取通常只涉及几张核心表,比如orders、customers、products。用app_db.*授权等于把未来新增的敏感表(如user_credentials)自动开放——你根本不知道下个版本会上什么表。
- 先确认ETL实际访问的表:开
general_log跑一轮全量抽取,再查mysql.general_log中SELECT语句的目标表 - 逐表授权:
GRANT SELECT ON app_db.orders TO 'etl_user'@'10.10.20.%'; GRANT SELECT ON app_db.customers TO 'etl_user'@'10.10.20.%'; - 表名含特殊字符(如
fact-sales)必须用反引号:GRANT SELECT ON app_db.`fact-sales` TO 'etl_user'@'10.10.20.%';
必须显式回收information_schema和performance_schema读权限
MySQL默认允许所有账号读information_schema.tables这类元数据,ETL工具一旦出bug或被注入,就能自动发现库内所有表结构,甚至猜出敏感表名。这不是配置错,是默认行为。
MySQL 数据库管理技能,能够通过自然语言查询和管理数据库,支持 SELECT/INSERT/UPDATE/DELETE、表管理、备份恢复等操作。当用户提及 MySQL、数据库查询、建表或数据备份时使用此技能。
- 执行
REVOKE SELECT ON information_schema.* FROM 'etl_user'@'10.10.20.%';(需SUPER或SYSTEM_VARIABLES_ADMIN权限) - 同样处理
performance_schema:REVOKE SELECT ON performance_schema.* FROM 'etl_user'@'10.10.20.%'; - MySQL 8.0.29+可设
show_compatibility_56=OFF辅助限制,但REVOKE才是根本解
备份类权限(如LOCK TABLES)不能直接给ETL账号
有些ETL工具(如老版Talend或自研脚本)会尝试加锁保证一致性,但这不是ETL该干的事——锁表会阻塞线上业务。ETL应该用快照读(MVCC)或从备库拉取,而不是在主库上抢锁。
- 禁止授予
LOCK TABLES、RELOAD、BACKUP_ADMIN等物理操作权限 - 如果ETL确实报错
ERROR 1227 (42000): Access denied; you need (at least one of) the LOCK TABLES privilege(s),说明它设计有缺陷,应改用--single-transaction或切到只读备库 - 真正需要一致性导出时,让DBA用
mysqldump --single-transaction配合专用备份账号,而非把权限塞给ETL账号
最易被忽略的是权限缓存:REVOKE后不执行FLUSH PRIVILEGES,旧权限仍生效;还有角色未激活问题——MySQL 8.0+用角色封装权限时,SET DEFAULT ROLE这步漏掉,SHOW GRANTS里根本看不到已授的权限。










