show grants是确认file权限的唯一可靠方式,因mysql.user表中file_priv字段仅为历史快照,不反映实时权限状态;必须用show grants for 'user'@'host'验证是否真正回收,且需配合secure_file_priv配置收紧与应用逻辑改造。

直接回收 FILE 权限比调 secure_file_priv 更有效,且必须配合配置收紧才真正阻断提权链。
为什么 SHOW GRANTS 是确认 FILE 权限的唯一可靠方式
mysql.user 表里的 File_priv 字段只是快照值,不反映当前生效状态。比如你已执行 REVOKE FILE ON *.* FROM 'app_user'@'10.20.30.%',但 SELECT File_priv FROM mysql.user 仍可能显示 Y——这是历史残留,不是真实权限。
正确验证方法是:
- 用有权限的账号执行
SHOW GRANTS FOR 'app_user'@'10.20.30.%',若结果里没出现FILE,说明已撤干净 - 若看到
GRANT FILE ON *.* TO ...,就说明还没回收 - 特别注意 root 用户:很多部署默认给 root 开全权限,但
FILE对管理账号非必需,应单独剥离
REVOKE FILE 必须写 ON *.*,不能省略或改范围
FILE 是全局权限,MySQL 不支持库级或表级粒度。写错作用域会导致静默失败:
- ✅ 正确:
REVOKE FILE ON *.* FROM 'app_user'@'10.20.30.%' - ❌ 错误:
REVOKE FILE ON app_db.* FROM ...→ 报错ERROR 1221 (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES - ❌ 错误:
REVOKE FILE FROM ...→ 语法不合法,会报错
执行后必须立刻验证:用该用户连接,尝试 SELECT 'test' INTO OUTFILE '/tmp/x.txt',应返回 ERROR 1045 (28000)。
secure_file_priv 配置不当会让 FILE 权限回收形同虚设
即使回收了 FILE 权限,如果 secure_file_priv 设为空字符串(''),旧版本 MySQL(如 5.6)在特定条件下仍可能绕过限制;设为 /tmp 则存在符号链接覆盖风险。
- 查当前值:
SELECT @@secure_file_priv,返回NULL表示禁用,最安全 - 生产环境应设为专用目录,例如
/var/lib/mysql-files/,并在my.cnf中显式配置:secure_file_priv = /var/lib/mysql-files - 该配置**必须重启 mysqld 生效**,
SET GLOBAL无法动态修改 - 目录权限要同步收紧:
sudo chown mysql:mysql /var/lib/mysql-files且chmod 750,禁止其他用户写入
回收后还要检查代码是否误依赖 FILE 功能
应用账号几乎从不需要 FILE 权限。一旦回收,如果业务报错 ERROR 1045 (28000): Access denied; you need (at least one of) the FILE privilege(s) for this operation,说明代码里用了 SELECT ... INTO OUTFILE 或 LOAD DATA INFILE。
- 这不是开权限的理由,而是要改逻辑:导出改用
mysqldump或应用层拼接 CSV - 导入改用客户端工具或
INSERT ... VALUES批量插入 - 尤其警惕 ORM 框架自动生成的导出语句,需审计 SQL 日志定位源头
真正的安全边界在于:权限回收 + 配置锁定 + 应用适配三者缺一不可,漏掉任一环都可能被绕过。











