最可靠导出CSV到本地的方式是MySQL客户端命令行加--batch和重定向,而非SELECT...INTO OUTFILE(仅写入服务端);复杂场景应使用Python或Node.js脚本,自动处理引号、转义、编码及分页。

用 SELECT ... INTO OUTFILE 导出到服务器磁盘(但不是你本地)
很多人第一反应是用 SELECT ... INTO OUTFILE,比如:
SELECT * FROM users INTO OUTFILE '/tmp/users.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n';
这确实能生成 CSV,但文件写在 MySQL 服务端的文件系统里(比如 /tmp/),不是你的本地电脑。你还得再用 scp 或 SFTP 手动拉下来——而且前提是 MySQL 用户有对应目录的写权限,secure_file_priv 也得放开。
常见错误现象:ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option... 或 ERROR 1045 (28000): Access denied...
-
secure_file_priv默认常设为/var/lib/mysql-files/或NULL(禁用所有导出) - 即使路径合法,你也拿不到那个文件,除非你有服务器 SSH 权限
- 不适用于云数据库(如阿里云 RDS、AWS RDS),它们通常禁用
INTO OUTFILE
用 MySQL 客户端命令行加 --batch 和重定向(真正导出到本地)
这才是最常用、最可靠、不需要服务端权限的方式:靠客户端自己格式化输出,再用 shell 重定向保存到本地文件。
执行前确保你用的是标准 MySQL CLI(不是 MySQL Shell / mysqlsh),且终端支持 UTF-8 编码(否则中文会乱码):
mysql -u root -p -e "SELECT id,name,email FROM users;" mydb > users.csv
但这样导出的是制表符分隔、无引号、无表头的纯文本。要接近 CSV 标准,得加参数:
-
--batch(或简写-B):用 tab 分隔字段,自动转义换行符 -
--raw:避免反斜杠转义(比如把\n当字面量而非换行) -
--skip-column-names:去掉列名行(否则第一行是字段名,但没引号、没逗号) - 用
sed或awk后处理成逗号分隔(简单场景下可接受)
更实用的一行命令(含表头、逗号分隔、双引号包裹):
mysql -u root -p -N -s -e "SELECT CONCAT('\"',id,'\",\"',name,'\",\"',email,'\"') FROM users;" mydb > users.csv
说明:-N 去列名,-s 精简模式(减少空格),CONCAT 手动拼 CSV 格式。注意:如果字段本身含双引号或换行,这个方案会出错——它只适合干净数据。
用 mysqldump 的 --tab 模式?别试了
mysqldump --tab 看起来像能导出 CSV,但它底层调用的仍是 SELECT ... INTO OUTFILE,所以同样受限于 secure_file_priv 和服务端权限。
运行后你会看到两个文件:table.sql(建表语句)和 table.txt(数据),但后者依然在服务端,不是本地。
典型错误:mysqldump: Got error: 1290: ... secure_file_priv —— 这个报错和 INTO OUTFILE 完全一致,本质是同一条限制路径。
复杂数据怎么办?Python 或 Node.js 脚本才是稳解
当字段含逗号、双引号、换行符,或需要 UTF-8 BOM、日期格式转换、大结果集分页时,手拼 SQL 或 CLI 重定向都会翻车。
推荐用 Python + csv 模块,它自动处理引号、转义、编码:
import csv
import pymysql
<p>conn = pymysql.connect(host='localhost', user='root', password='xxx', db='mydb')
cursor = conn.cursor()
cursor.execute("SELECT id, name, email FROM users")
with open('users.csv', 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.writer(f, quoting=csv.QUOTE_MINIMAL)
writer.writerow([desc[0] for desc in cursor.description]) # 表头
writer.writerows(cursor.fetchall())</p>
关键点:
-
encoding='utf-8-sig'让 Excel 能正确识别中文(加 BOM) -
quoting=csv.QUOTE_MINIMAL只在必要时加引号,兼顾可读与合规 - 不用手动拼 SQL 字符串,天然防注入、防格式错乱
Node.js 同理,可用 mysql2 + fast-csv,逻辑类似。
真正容易被忽略的是:大表导出时内存占用。不要一次性 fetchall(),改用游标分批读取,否则 Python 进程可能 OOM。











