How to Export Data from MySQL to a CSV File

How to Export Data from MySQL to a CSV File

I export data out of MySQL more often than almost any other operation I perform as a working DBA — a finance team wants a spreadsheet, a data science colleague wants a clean dataset, a client wants a report they can open in Excel. Over the years I’ve learned there’s more than one right way to do this, and each method has tradeoffs around server access, formatting control, and file size that I want to walk through properly.

Method 1: SELECT INTO OUTFILE

This is the fastest method because it runs entirely on the MySQL server and writes the file directly, without round-tripping data through a client.

SELECT customer_id, name, city, created_at
FROM customers
INTO OUTFILE '/var/lib/mysql-files/customers.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';

Output file (customers.csv):

"1","Ayesha","Lahore","2026-01-05 10:00:00"
"2","Bilal","Karachi","2026-01-15 11:30:00"
"3","Sara","Lahore","2026-02-02 09:45:00"

A few things I always remember about this method:

SHOW VARIABLES LIKE 'secure_file_priv';

Adding a Header Row

SELECT INTO OUTFILE doesn’t include column headers by default. I use a UNION trick to add one:

(SELECT 'customer_id', 'name', 'city', 'created_at')
UNION ALL
(SELECT customer_id, name, city, created_at FROM customers)
INTO OUTFILE '/var/lib/mysql-files/customers_with_header.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';

Method 2: mysqldump with –tab

For dumping entire tables quickly, mysqldump supports a tab-separated export mode:

mysqldump --tab=/var/lib/mysql-files/ --fields-terminated-by=',' --fields-enclosed-by='"' mydatabase customers

This produces both a .sql file (the table structure) and a .txt file (the data), and requires the --tab target directory to be accessible to the MySQL server process, similar to the secure_file_priv restriction on INTO OUTFILE, since mysqldump --tab internally uses the same mechanism.

Method 3: The mysql Command-Line Client

When I don’t have server-side file write access (very common on managed cloud databases like RDS or Cloud SQL), I export from the client side instead, which writes the file on whatever machine is running the command — usually my own laptop or a jump host — rather than the database server.

mysql -u root -p --database=mydatabase \
  --execute="SELECT customer_id, name, city, created_at FROM customers" \
  --batch --raw | sed 's/\t/,/g' > customers.csv

Or, more cleanly, using the built-in tab-separated batch mode and then converting:

mysql -u root -p mydatabase -e "SELECT * FROM customers" > customers.tsv

This is my default method for managed cloud MySQL instances where I never have OS-level access to the database server itself.

Method 4: MySQL Workbench / GUI Tools

For one-off exports, I often just use MySQL Workbench’s built-in “Export Resultset to CSV” option after running a query, or phpMyAdmin’s export tab for web-based environments. These tools handle the client-side file writing and formatting details automatically, which is convenient for non-technical team members who need occasional exports without touching the command line.

Handling Special Characters and Encoding

CSV exports can go wrong in subtle ways if I’m not careful:

SELECT customer_id, name, city
FROM customers
INTO OUTFILE '/var/lib/mysql-files/customers_utf8.csv'
CHARACTER SET utf8mb4
FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '\\'
LINES TERMINATED BY '\n';

Exporting Query Results, Not Just Whole Tables

The real power of SELECT INTO OUTFILE is that it works on any query, not just a raw table dump — I use it constantly for exporting filtered, joined, or aggregated results.

SELECT c.name, SUM(o.amount) AS total_spent
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.name
HAVING SUM(o.amount) > 300
INTO OUTFILE '/var/lib/mysql-files/high_value_customers.csv'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n';

Export Workflow Diagram

flowchart TD
    A[Need to export data] --> B{Do I have server filesystem access?}
    B -->|Yes| C[SELECT ... INTO OUTFILE or mysqldump --tab]
    B -->|No, e.g. managed cloud DB| D[mysql client -e query redirected to local file]
    C --> E[File written on DB server]
    D --> F[File written on local/client machine]
    E --> G[Retrieve file via SSH/SCP if needed]
    F --> H[Ready to use directly]

Real-World DBA Scenarios

Security Considerations

Common Mistakes

Troubleshooting Table

SymptomLikely CauseFix
ERROR 1290: The MySQL server is running with the --secure-file-priv optionTarget path isn’t in the allowed directoryExport to the path shown by SHOW VARIABLES LIKE 'secure_file_priv'
ERROR 1086: File already existsPrevious export file wasn’t removedDelete/rename the old file, or export to a new filename
CSV opens with garbled special characters in ExcelCharacter set mismatch or missing BOM for UTF-8Export with CHARACTER SET utf8mb4, and consider adding a UTF-8 BOM for Excel compatibility
Columns misaligned in the resulting CSVUnescaped commas or quotes within field valuesUse ENCLOSED BY '"' and ESCAPED BY '\\'

FAQs

Can I export directly to my local machine from a remote MySQL server? Not with SELECT INTO OUTFILE, which always writes on the server. Use the mysql command-line client with output redirection, or retrieve the server-side file via SCP/SFTP afterward.

Why do I get a “secure-file-priv” error? MySQL restricts file export/import paths for security reasons; check SHOW VARIABLES LIKE 'secure_file_priv' for the allowed directory.

How do I include column headers in the CSV? SELECT INTO OUTFILE doesn’t add headers automatically — use a UNION ALL with a literal header row, or add headers with a script after export.

What’s the difference between mysqldump and SELECT INTO OUTFILE? mysqldump is generally used for full table/database backups (including structure), while SELECT INTO OUTFILE is better suited for exporting the exact result of a specific query, including joins and filters.

Is there a size limit for exported files? No hard MySQL-imposed limit, but very large exports can be constrained by disk space on the server and by max_allowed_packet if going through certain client-based export paths.

Interview Questions

  1. What’s the difference between server-side and client-side CSV export in MySQL?
  2. What privilege is required for SELECT INTO OUTFILE, and why is it security-sensitive?
  3. How would you add a header row to a SELECT INTO OUTFILE export?
  4. What does secure_file_priv control, and how would you check its current value?
  5. How would you export data from a managed cloud MySQL instance where you don’t have server filesystem access?
  6. What character encoding considerations matter when exporting international data to CSV?
  7. How would you export the result of a multi-table JOIN with aggregation to CSV?

Optimization Tips

Summary and Key Takeaways

Exporting data from MySQL to CSV comes down to choosing the right tool for your access level and use case: SELECT INTO OUTFILE is the fastest, most flexible option when you have server filesystem access and want to export any arbitrary query result; mysqldump --tab suits full-table dumps; and the mysql command-line client is my fallback for managed cloud databases without direct server access. Getting encoding, delimiters, and headers right up front saves a lot of downstream headaches for whoever consumes the file next, and treating exported CSVs with the same security discipline as the database itself is non-negotiable when sensitive data is involved.

References

Exit mobile version