MySQL 8.0+ 默认禁用 LOAD DATA LOCAL INFILE 是出于安全策略,需同时满足服务端 secure_file_priv 非空且客户端显式启用 local_infile 才能使用。

为什么 LOAD DATA LOCAL INFILE 默认被禁用
MySQL 8.0+ 客户端默认关闭 local_infile,不是 bug,是安全策略。服务端(secure_file_priv)和客户端(local_infile)双层限制,缺一不可。一旦报错 ERROR 1148 (42000): The used command is not allowed with this MySQL version,大概率是这里卡住了。
常见误区:只改服务端配置、或只在命令行加 --local-infile=1,但没同步改客户端驱动行为(比如 Python 的 pymysql 或 Node.js 的 mysql2 都要显式启用)。
- 服务端需确认
secure_file_priv值不为空(否则所有INFILE类操作全禁);设为''表示不限制路径(不推荐),设为具体目录如/var/lib/mysql-files/更安全 - 客户端连接时必须显式开启:MySQL CLI 加
--local-infile=1;JDBC URL 加;<code>pymysql.connect(local_infile=True) - MySQL 8.0.27+ 还要求服务端显式启用
local_infile=ON(以前靠secure_file_priv推断)
如何安全启用本地文件导入(服务端 + 客户端联动)
不能只改一处。服务端放开路径权限,客户端打开开关,二者匹配才生效。重点不是“能不能用”,而是“只允许从哪读、谁有权限读”。
- 检查服务端现状:
SELECT @@secure_file_priv, @@local_infile;—— 若前者为NULL,说明未配置路径白名单;后者为OFF则需手动开 - 修改
my.cnf(Linux)或my.ini(Windows),在[mysqld]下加两行:secure_file_priv = /tmp/mysql_local_infile<br>local_infile = ON
然后重启mysqld - 确保目标目录存在且 MySQL 进程可读:
sudo mkdir -p /tmp/mysql_local_infile && sudo chown mysql:mysql /tmp/mysql_local_infile - 客户端连接后验证:
SHOW VARIABLES LIKE 'local_infile';返回ON才算通路走通
LOAD DATA LOCAL INFILE 在不同客户端的启用方式差异
命令行工具、Python、Node.js 启用逻辑完全不同,且容易漏掉驱动层开关。尤其注意:即使服务端开了,驱动默认仍可能屏蔽该指令。
- MySQL CLI:
mysql --local-infile=1 -u root -p—— 必须带参数,交互式里再执行SET GLOBAL local_infile = 1无效(这是服务端变量,不影响客户端行为) - Python + PyMySQL:
pymysql.connect(..., local_infile=True),且确保安装时没禁用local_infile支持(部分二进制包默认裁剪) - Python + mysql-connector-python:
mysql.connector.connect(..., allow_local_infile=True),还要在连接后执行cursor.execute("SET SESSION local_infile = 1")(部分版本需要) - Node.js + mysql2:
new Pool({ ..., enableLocalInfile: true }),不设这个选项,LOAD DATA LOCAL直接被驱动静默拒绝
为什么用绝对路径还报错“File not found”
不是路径写错了,是 MySQL 客户端在找文件时,根本没按你写的路径去读——它只认自己启动时工作目录下的相对路径,或服务端 secure_file_priv 指定的绝对路径(仅对非 LOCAL 版本有效)。
-
LOAD DATA LOCAL INFILE '/home/user/data.csv':客户端进程必须有权限读这个路径,且路径对客户端进程是可达的(比如 Docker 容器里运行的客户端,宿主机路径无效) - Windows 下反斜杠要双写:
LOAD DATA LOCAL INFILE 'C:\temp\data.csv',单斜杠或原始字符串不处理转义会失败 - 如果服务端
secure_file_priv设为/var/lib/mysql-files/,那LOCAL关键字就绕过这个限制——但客户端仍要能访问你指定的任意本地路径;去掉LOCAL才强制走服务端路径白名单 - SELinux 或 AppArmor 可能拦截文件读取,错误日志里看不到明显提示,需查
audit.log或临时setenforce 0测试
最稳妥的做法:把文件放到 secure_file_priv 指定目录下,去掉 LOCAL,用服务端路径加载——虽然多一步拷贝,但权限链清晰、审计友好、不依赖客户端环境。










