mysql 8.0 默认禁用 load data local infile,需同时开启服务端 local_infile、客户端 --local-infile=1 及驱动层对应参数,并绕过 secure_file_priv 限制;最安全方式是改用服务端 load data infile。

MySQL 8.0 默认禁用 LOAD DATA LOCAL INFILE,不是“没配好”,而是必须显式打通服务端、客户端、驱动三层开关,并绕过 secure_file_priv 限制才能走通——漏掉任意一层都会报 ERROR 1148 或 ERROR 2068。
检查服务端 local_infile 和 secure_file_priv 是否就绪
只查 @@local_infile 不够,必须同时确认两个变量:
-
SELECT @@local_infile;返回ON(或1),说明服务端允许接收 LOCAL 请求 -
SELECT @@secure_file_priv;不能为NULL;若值是具体路径(如/var/lib/mysql-files/),则LOAD DATA LOCAL INFILE实际仍可用(注意:它约束的是LOAD DATA INFILE,但部分客户端会受其影响);若你看到secure_file_priv为空字符串(''),说明服务端允许从任意路径读取——但这在生产环境极度危险,不建议设为空 - 如果
secure_file_priv是非空路径,且你坚持要用LOCAL,那它本身不影响LOCAL流程,但某些旧版客户端或驱动会误判并拦截,此时应优先确保local_infile和客户端开关正确
MySQL CLI 客户端必须带 --local-infile=1 启动
命令行工具默认不启用该功能,即使服务端开了也无效:
- 正确连接方式:
mysql --local-infile=1 -u root -p - 验证是否生效:登录后立即执行
SELECT @@local_infile;,返回ON才算客户端通道打开 - 避免配置冲突:在
~/.my.cnf的[client]段加loose-local-infile = 1(注意是loose-local-infile,不是local-infile;前者兼容性更好,后者在某些版本会被忽略) - 切勿在 Docker 或脚本中漏掉
--local-infile=1:比如docker run mysql:8.0 mysql -h db -u user -p --local-infile=1,否则白配服务端
Python 驱动需显式传参,且不同库参数名不同
PyMySQL、mysql-connector-python、mysql2 等主流驱动默认禁用 LOCAL INFILE,不会继承 CLI 的配置:
- PyMySQL:
pymysql.connect(..., local_infile=True)—— 注意不是True默认值,很多打包版本直接裁剪了该功能 - mysql-connector-python:
mysql.connector.connect(..., allow_local_infile=True) - mysql2(Node.js):
new Pool({ ..., localInfile: true }) - 关键点:这些参数必须在连接初始化时传入,运行时调用
SET GLOBAL local_infile = ON对驱动层完全无效
真正安全的加载方式:别用 LOCAL,改用服务端 LOAD DATA INFILE
只要文件能放到 MySQL 服务端机器上,就应优先走这条路径——它规避了“客户端本地读取”这一最大攻击面:
- 把 CSV 文件拷到服务端(如
/var/lib/mysql-files/data.csv),确保属主为mysql:mysql - 执行:
LOAD DATA INFILE '/var/lib/mysql-files/data.csv' INTO TABLE t FIELDS TERMINATED BY ','; - 前提:用户必须有
FILE权限(GRANT FILE ON *.* TO 'user'@'%';),但该权限只影响服务端读取,不构成反向泄露风险 - 如果
secure_file_priv设为非空目录,就必须把文件放进去;设为空字符串虽方便,但等于开放任意文件读取,生产环境禁止
最常被忽略的一点:即使你按步骤全打开了 LOCAL INFILE,只要客户端进程(比如 PHP-FPM、Python 进程)运行在数据库服务器同一台机器上,攻击者仍可能通过 SQL 注入让这个“客户端”去读取 /etc/shadow 并回传——所以除非业务强依赖,否则永远优先考虑服务端 INFILE 路径。











