secure_file_priv有三种值:null(禁用导出)、具体路径(仅限该目录)、空字符串(不限制但危险);需修改配置文件并重启,且目录权限和docker挂载缺一不可;select into outfile仅支持文件名,不支持路径。

查 secure_file_priv 当前值,先看拦不拦你
导出失败报 ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement,八成就是它在起作用。连上 MySQL 后直接执行:
SHOW VARIABLES LIKE 'secure_file_priv';
返回结果只有三种可能:
-
NULL:彻底禁用SELECT INTO OUTFILE和LOAD DATA INFILE,任何路径都写不了 -
/var/lib/mysql-files/(或类似具体路径):只允许读写这个目录,其他路径一律拒绝 -
''(空字符串):不限制路径——但这是危险配置,生产环境严禁这么设
注意:secure_file_priv 是只读变量,SET 命令改不动,必须改配置文件再重启。
改配置文件,路径和权限缺一不可
别只改配置,漏掉目录权限照样失败。操作顺序必须是:
- 选一个你打算用的导出目录,比如
/data/mysql-export,先创建它:sudo mkdir -p /data/mysql-export - 把目录所有权交给 MySQL 进程用户(通常是
mysql:mysql):sudo chown mysql:mysql /data/mysql-export - 编辑 MySQL 配置文件(常见位置:
/etc/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf),在[mysqld]段下加一行:secure_file_priv = /data/mysql-export - 重启服务:
sudo systemctl restart mysql(或mysqld)
重启后务必再查一遍 SHOW VARIABLES LIKE 'secure_file_priv',确认值已更新。Docker 环境还要额外挂载该目录,否则容器内路径存在但宿主机不可见。
导出时路径必须绝对,且不能带子目录层级
SELECT INTO OUTFILE 只接受相对于 secure_file_priv 目录的**文件名**,不支持路径遍历:
- ✅ 正确:
SELECT * INTO OUTFILE 'report.csv' FROM users;→ 实际写入/data/mysql-export/report.csv - ❌ 错误:
SELECT * INTO OUTFILE '/tmp/report.csv' FROM users;→ 报 1290 错误 - ❌ 错误:
SELECT * INTO OUTFILE 'subdir/report.csv' FROM users;→ 即使subdir在secure_file_priv下也失败,MySQL 不解析子目录
如果真要分类存放,得提前在 secure_file_priv 目录下建好子目录,并确保 MySQL 用户对其有写权限,但语句里仍只能写文件名,不能带路径。
别混淆 mysqldump 和 SELECT INTO OUTFILE 的权限机制
mysqldump 是客户端工具,走的是网络协议,不受 secure_file_priv 约束——它导出到本地任意可写路径(比如 ~/backup.sql)。而 SELECT INTO OUTFILE 是服务器端操作,文件由 MySQL 进程直接写入磁盘,才强制走 secure_file_priv。
所以:
- 想导出大表、需要 CSV 格式、或后续要用
LOAD DATA INFILE快速回填 → 必须配好secure_file_priv - 只是日常备份整个库 → 用
mysqldump -u user -p db > backup.sql,完全绕过这个限制
最容易忽略的点:很多人以为配了 secure_file_priv 就万事大吉,却忘了 mysqld 进程对目标目录没有写权限,或者 Docker 容器没做 volume 挂载——这两处卡住,比配置本身更常见。











