Bulk-importing a .csv file into MySQL or MariaDB turns spreadsheet-shaped data into queryable rows with minimal manual work. The approach is useful for migrations, one-off backfills, analytics staging, and feeding applications from exports generated by other systems.
LOAD DATA [LOCAL] INFILE parses input as a stream of lines, splits each line into fields, and assigns those fields to columns in an existing table. With LOCAL, the client reads the file from the machine running the mysql client and sends it over the connection; without LOCAL, the server reads from its own filesystem, typically subject to secure_file_priv restrictions.
Imports succeed only when the CSV layout matches the target schema, including column order, quoting, character set, and newline conventions. Many installations disable local_infile by default for security, so enabling it temporarily (and disabling it again afterwards) keeps risk contained. When data types do not match—dates, decimals, enums—values may be coerced or rejected, making a warning review an important post-import check.
$ mysql --local-infile=1 -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 177 Server version: 8.0.44 MySQL Community Server - GPL ##### snipped ##### mysql>
LOCAL reads the file from the client host running mysql, while non-LOCAL reads from the database server filesystem.
mysql> USE appdb; Database changed
mysql> SHOW VARIABLES LIKE 'local_infile'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | local_infile | OFF | +---------------+-------+ 1 row in set (0.01 sec)
mysql> SET GLOBAL local_infile = 1; Query OK, 0 rows affected (0.00 sec)
Leaving local_infile enabled longer than necessary increases risk during connections to untrusted servers or intermediaries.
mysql> SHOW VARIABLES LIKE 'secure_file_priv'; +-----------------+-----------------------+ | Variable_name | Value | +-----------------+-----------------------+ | secure_file_priv| /var/lib/mysql-files/ | +-----------------+-----------------------+ 1 row in set (0.00 sec)
A non-empty value restricts non-LOCAL LOAD DATA INFILE reads to that directory on the server.
mysql> DESCRIBE import_orders; +-------------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+---------------+------+-----+---------+-------+ | id | int | NO | PRI | NULL | | | customer_id | int | NO | | NULL | | | total | decimal(10,2) | NO | | NULL | | | created_at | datetime | NO | | NULL | | +-------------+---------------+------+-----+---------+-------+ 4 rows in set (0.00 sec)
List columns in the LOAD DATA statement when the CSV omits table columns (for example, an AUTO_INCREMENT id).
mysql> LOAD DATA LOCAL INFILE '/root/sg-work/imports/orders-import.csv'
-> INTO TABLE import_orders
-> CHARACTER SET utf8mb4
-> FIELDS TERMINATED BY ','
-> OPTIONALLY ENCLOSED BY '"'
-> LINES TERMINATED BY '\n'
-> IGNORE 1 LINES;
Query OK, 5 rows affected (0.00 sec)
Records: 5 Deleted: 0 Skipped: 0 Warnings: 0
Use IGNORE 1 LINES only when the first row is a header, and switch LINES TERMINATED BY '\r\n' for Windows-style newlines.
mysql> SHOW WARNINGS LIMIT 10; Empty set (0.00 sec)
Warnings often indicate truncation, invalid dates, or character set mismatches even when rows load successfully.
mysql> SELECT COUNT(*) AS imported_rows FROM import_orders; +---------------+ | imported_rows | +---------------+ | 5 | +---------------+ 1 row in set (0.00 sec)
mysql> SELECT * FROM import_orders ORDER BY id LIMIT 5; +----+-------------+--------+---------------------+ | id | customer_id | total | created_at | +----+-------------+--------+---------------------+ | 10 | 1 | 249.99 | 2025-12-24 14:12:40 | | 11 | 2 | 89.50 | 2025-12-24 14:12:40 | | 12 | 3 | 149.00 | 2025-12-24 14:12:40 | | 13 | 1 | 249.99 | 2025-12-24 14:13:03 | | 14 | 2 | 89.50 | 2025-12-24 14:13:03 | +----+-------------+--------+---------------------+ 5 rows in set (0.00 sec)
mysql> SET GLOBAL local_infile = 0; Query OK, 0 rows affected (0.00 sec)
Some environments apply the global value to new connections, so existing sessions may require reconnecting to inherit the change.
mysql> EXIT; Bye