The ProblemYou hit 'Enter' on a LOAD DATA LOCAL INFILE command, expecting a quick data import. Instead, MySQL stops you cold with this error:
ERROR 2068 (HY000): LOAD DATA LOCAL INFILE file request rejected due to restrictions on access
MySQL 8.0 tightened the screws on security. Even if your file permissions are wide open (777), MySQL blocks the operation by default. This prevents a 'rogue server' exploit where a malicious database server could theoretically trick a client into uploading sensitive local files like /etc/passwd or SSH keys.
The Root Cause: A Two-Way HandshakeTo move a file from your local machine to the server, both ends of the connection must agree to the transfer. It is a two-step verification process:
- The MySQL Server must have the
local_infilesystem variable set toON.- The MySQL Client (your terminal, Python script, or PHP app) must explicitly signal that it wants to send local data.If either side says 'No,' the entire transfer fails with Error 2068.
Step 1: Enable local_infile on the ServerStart by checking your server's current status. Run this in your MySQL shell:
SHOW GLOBAL VARIABLES LIKE 'local_infile';
If the result is OFF, you can enable it instantly without a restart. Run this command:
SET GLOBAL local_infile = 1;
Making the Change PermanentThe command above only lasts until the next time the database restarts. To make it stick, find your configuration file—usually /etc/mysql/my.cnf or /etc/my.cnf—and add these lines:
[mysqld]
local_infile=1
Apply the changes by restarting the service:
sudo systemctl restart mysql
Step 2: Enable local_infile on the Client SideServer-side configuration is only half the battle. Your connection method must also permit the transfer.
Option A: The Command Line Interface (CLI)When you log in, you must include the --local-infile flag. A standard login command looks like this:
mysql --local-infile=1 -u db_user -p -h 127.0.0.1 your_database
Option B: Python (mysql-connector-python)If you're automating imports with Python, the standard connection dictionary isn't enough. You must pass allow_local_infile=True as a parameter:
import mysql.connector
connection = mysql.connector.connect(
user='admin',
password='your_password',
host='127.0.0.1',
database='sales_data',
allow_local_infile=True
)
Option C: PHP (PDO)For PHP applications, set the attribute during the PDO instantiation. This is a common requirement for Laravel or custom CMS setups:
$options = [
PDO::MYSQL_ATTR_LOCAL_INFILE => true,
];
$db = new PDO("mysql:host=localhost;dbname=app_db", "user", "pass", $options);
Step 3: Test the ImportTry running your import again. For a file with 50,000 rows, use a structured command like this:
LOAD DATA LOCAL INFILE '/tmp/users_list.csv'
INTO TABLE users
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
If you see Query OK, 50000 rows affected, the restriction is officially lifted.
Security Best PracticesEnabling local_infile globally can be risky in multi-tenant environments. If you are working with highly sensitive data, consider these safer alternatives:
- The secure_file_priv approach: Move your CSV to the directory specified by
SHOW VARIABLES LIKE 'secure_file_priv';(often/var/lib/mysql-files/). Then, useLOAD DATA INFILE(omitting theLOCALkeyword). This lets the server read the file directly from its own disk.- Restrict Privileges: Grant theFILEprivilege only to specific administrative users rather than the general application user.In most development environments, enablinglocal_infileis the standard fix, but always disable it in production if you don't strictly need it for daily operations.

