必须限制生产库执行直接删库、清空表、修改系统表、跨库写入等高危操作;应显式收回drop权限、禁用process/super权限、用mysql 8.0角色隔离ddl权限、避免grant all、启用审计日志并过滤敏感关键词。

哪些操作必须限制在生产库上执行
直接删库、清空表、修改系统表、跨库写入这类操作,在生产环境应默认禁止。MySQL 本身不提供“只允许 select/INSERT”的细粒度语义控制,DROP database、TRUNCATE table、ALTER TABLE ... DROP column 等命令一旦被误执行,恢复成本极高。
实操建议:
- 用
REVOKE DROP ON *.* FROM 'user'@'host'显式收回所有DROP权限,而非依赖“没给就不让干”的默认逻辑 - 对运维账号(如
dba_admin)启用sql_log_bin = OFF临时会话变量,避免 DDL 操作被主从复制放大影响 - 禁止应用账号拥有
PROCESS或SUPER权限——这两个权限可绕过大多数审计与限制机制
如何用 MySQL 8.0 的角色(ROLE)隔离敏感操作权限
MySQL 5.7 不支持角色,升级到 8.0 后,可以用角色把高危权限集中管理,避免给每个账号重复赋权或漏收权。
实操建议:
- 创建专用角色:
CREATE ROLE 'ddl_operator'; GRANT ALTER, DROP, CREATE ON *.* TO 'ddl_operator'; - 仅在需要执行 DDL 的临时会话中激活:
SET ROLE 'ddl_operator';,且该语句需配合activate_all_roles_on_login = OFF配置项防止自动生效 - 检查当前会话有效权限用:
SHOW GRANTS;,注意它不显示角色隐含权限,要加for CURRENT_USER才能看到实际生效项
为什么不能只靠 GRANT ALL PRIVILEGES 来授权
GRANT ALL PRIVILEGES 在 MySQL 中是“当前版本所有权限”的快照,不是动态集合。新版本新增的权限(如 8.0 的 BACKUP_ADMIN、CLONE_ADMIN)不会自动加入已有 ALL 授权,但旧版脚本重跑时又可能意外授予它们。
实操建议:
- 永远显式列出所需权限:
GRANT SELECT, INSERT, UPDATE ON db.tbl TO 'app'@'%';,哪怕多打几行 - 用
SELECT * FROM mysql.role_edges;审计角色继承关系,避免“谁给了谁什么角色”变成黑盒 - 定期导出权限快照:
mysqldump --no-data --skip-triggers mysql user db tables_priv columns_priv,比靠记忆更可靠
SQL 审计日志怎么开才真正有用
MySQL 自带的 general_log 只记录语句文本,不记录执行者、客户端 IP、是否成功;企业级审计需要能回溯“谁在什么时候、从哪台机器、执行了什么、结果如何”。
实操建议:
- 开启
audit_log插件(需企业版)或用社区版替代方案:mysqlbinlog+ 解析 binlog 事件类型(QUERY_EVENT/XID_EVENT),但注意 binlog 默认不记录SELECT - 设置
log_output = 'TABLE'并搭配performance_schema.audit_log_summary_by_account视图做聚合分析,比文件日志更易查询 - 敏感操作关键词过滤(如匹配
^DROP|^TRUNCATE|^delete FROM [^ ]+ WHERE$)必须在应用层或代理层(如 ProxySQL)做,MySQL 服务端无正则审计能力
权限配置不是一劳永逸的事——角色变更、账号复用、临时提权后忘记回收,这些才是线上事故最常出现的环节。真正有效的策略,是让“高危操作必须经过两步确认”成为基础设施的一部分,而不是指望人记住哪条命令不能敲。