mysql命令行客户端是每个后端和运维都要打交道的工具。它不只是"敲 SQL 的窗口"——垂直输出、批处理模式、tee、备份参数这些细节用好了能省很多事。本文聚焦客户端工具本身,SQL 语法部分见 SQL 命令使用教程。

一、连接服务器
1.1 基础连接
mysql -u root -p # 本地连接,回车后输入密码
mysql -h 127.0.0.1 -P 3306 -u app -p # 指定主机和端口
mysql -u root -p school_db # 连接后直接进入 school_db1.2 参数速查
| 参数 | 含义 | 示例 |
|---|---|---|
-u | 用户名 | -u app |
-p | 提示输入密码 | -p(单独写,别紧跟密码) |
-h | 主机地址 | -h db.example.com |
-P | 端口(大写) | -P 3307 |
-S | Unix socket 路径 | -S /var/run/mysqld/mysqld.sock |
-D | 连接后选中的数据库 | -D school_db |
-e | 执行一条语句后退出 | -e "SELECT 1" |
-B | 批处理模式(制表符分隔) | -B |
-N | 不输出列名 | -N |
--defaults-file | 指定配置文件 | --defaults-file=~/my.cnf |
1.3 别在命令行里写密码
mysql -u root -pMyPassword123 # ❌ 密码会出现在 ps 输出里,也不进 shell 历史命令行传的密码,同机上的任何用户都能通过 ps aux 看到。正确做法有两种:
方法一:用 mysql_config_editor 生成加密登录路径(推荐)
mysql_config_editor set --login-path=local --host=127.0.0.1 --user=root --password
# 之后连接:
mysql --login-path=local密码加密存在 ~/.mylogin.cnf,连接时可以彻底不写密码。
方法二:用权限 600 的配置文件
cat > ~/.my.cnf <<'EOF'
[client]
user=root
password=your_password
EOF
chmod 600 ~/.my.cnf之后 mysql 会自动读取,无需任何参数。
顺带说个冷门坑:
~/.mysql_history会把你在交互式会话里敲过的所有语句明文记下来,包括CREATE USER ... IDENTIFIED BY '明文密码'。多人共用账号的机器上,建议设export MYSQL_HISTFILE=/dev/null关掉,或者定期清理。
二、交互式使用
连上以后,除了 SQL,还有一批以反斜杠开头的客户端命令(注意:这些同样不是 SQL,不能写进 .sql 文件)。
| 命令 | 作用 |
|---|---|
\G | 以"每列一行"的垂直格式输出(最常用) |
\s | 显示服务器状态(版本、字符集、连接信息) |
\d | 修改默认语句结束符(默认 ;) |
\u dbname | 切换数据库(等价 USE) |
\c | 取消当前正在输入的语句 |
\q | 退出 |
\h / \? | 帮助 |
\e | 用编辑器编辑当前语句 |
\T file | 开启 tee,把输出同时写入文件 |
\t | 关闭 tee |
\P less | 设置分页器(翻页查看大结果集) |
source file.sql | 执行一个 SQL 文件 |
2.1 \G:查看宽表时的救星
SELECT * FROM mysql.user WHERE user = 'root' \G行尾写 \G(代替分号),输出会变成竖排:
*************************** 1. row ***************************
Host: localhost
User: root
Password: *
Select_priv: Y宽表一行几十列时,横排输出会折行折到看不清,\G 是对的解法。
2.2 输出格式
输出格式是客户端的启动选项,不是 SQL 语法:
mysql --table -u root -p school_db -e "SELECT * FROM students" # 表格(默认)
mysql --batch -B -u root -p school_db -e "SELECT * FROM students" # 制表符分隔,易被脚本解析
mysql --vertical-E -u root -p school_db -e "SELECT * FROM students" # 竖排(等价 \G)
mysql --html -u root -p school_db -e "SELECT * FROM students" # 输出 HTML 表格
mysql --xml -u root -p school_db -e "SELECT * FROM students" # 输出 XML常见误解:
SELECT * FROM t --html不是有效写法——--html是mysql命令的选项,要放在连接参数区,不能跟在 SQL 后面。同理\T是开启 tee(写文件),不是"表格格式"。
三、批处理与非交互执行
3.1 执行单条或多条语句
mysql -u root -p -e "SHOW DATABASES;"
mysql -u root -p school_db -e "SELECT COUNT(*) FROM students;"注意参数顺序:数据库名要放在 -e 之前,或者用 -D 指定。
mysql -u root -p -e "SELECT * FROM students" school_db # ❌ 报错:多余参数
mysql -u root -p school_db -e "SELECT * FROM students" # ✅ 正确
mysql -u root -p -D school_db -e "SELECT * FROM students" # ✅ 也正确3.2 执行脚本文件
mysql -u root -p school_db < script.sql # shell 重定向
mysql -u root -p school_db < script.sql > out.txt # 结果存文件在交互式会话里则用 source:
source /path/to/script.sql两者区别:< script.sql 是 shell 层面的输入重定向,整个文件作为输入流;source 是客户端命令,可以嵌套、可以使用相对路径(相对于当前工作目录)。
3.3 批处理模式适合脚本化
-B(batch)模式用制表符分隔列、每行一条记录,且不做终端美化,最适合被 awk/cut 处理:
mysql -B -N -u root -p school_db -e "SELECT id, name FROM students" | while IFS=$'\t' read -r id name; do
echo "id=$id name=$name"
done-N 去掉列名行,-B 让输出无边框。这两个参数组合是做数据导出/巡检脚本的标配。
3.4 出错时的行为
默认遇到错误就停止。如果希望"尽力执行、忽略单条失败",加 -f:
mysql -f -u root -p school_db < import.sql3.5 退出码
客户端把服务器返回的 SQL 错误映射为退出码,脚本里可以据此判断成败:
if ! mysql -u root -p school_db -e "SELECT 1" 2>/dev/null; then
echo "连接或执行失败"
fi四、用户与权限
-- 创建用户(MySQL 8 默认认证插件 caching_sha2_password)
CREATE USER 'app'@'localhost' IDENTIFIED BY 'StrongPass!2026';
-- 授权
GRANT SELECT, INSERT, UPDATE, DELETE ON school_db.* TO 'app'@'localhost';
-- 查看权限
SHOW GRANTS FOR 'app'@'localhost';
-- 撤销
REVOKE DELETE ON school_db.* FROM 'app'@'localhost';
-- 改密码 / 删用户
ALTER USER 'app'@'localhost' IDENTIFIED BY 'NewPass!2026';
DROP USER 'app'@'localhost';'user'@'host' 是 MySQL 的特色:同一个用户名从不同主机连进来,可以是完全不同的账号和权限。'app'@'localhost' 和 'app'@'%'(任意主机)是两个独立账号。授权后别忘了 FLUSH PRIVILEGES;(用 GRANT/CREATE USER 语句时通常自动生效,直接改 mysql.user 表才需要手动刷)。
五、导入导出
5.1 mysqldump 备份
# 备份单个库
mysqldump -u root -p school_db > school_db.sql
# 备份单张表
mysqldump -u root -p school_db students > students.sql
# 备份多个库(保留 CREATE DATABASE 语句)
mysqldump -u root -p --databases db1 db2 > dbs.sql
# 备份全部库
mysqldump -u root -p --all-databases > all.sql
# 压缩备份(推荐:SQL 文本压缩率很高)
mysqldump -u root -p --all-databases | gzip > all-$(date +%F).sql.gz生产环境必须加的参数:
mysqldump -u root -p \
--single-transaction \ # InnoDB 一致性快照,不锁表(关键!)
--routines \ # 导出存储过程和函数
--triggers \ # 导出触发器
--events \ # 导出事件调度
--set-gtid-purged=OFF \ # 跨实例恢复时避免 GTID 冲突
school_db > school_db.sql不加 --single-transaction 的话,备份期间会锁表,业务写入被阻塞。InnoDB 表一定加上(MyISAM 表它无效)。
只想导结构/只想导数据:
mysqldump -u root -p --no-data school_db > schema.sql # 仅结构
mysqldump -u root -p --no-create-info school_db > data.sql # 仅数据5.2 恢复
mysql -u root -p school_db < school_db.sql # 从文件恢复
gunzip < all-2026-09-22.sql.gz | mysql -u root -p # 从压缩文件恢复恢复大文件慢是常态,可以临时关掉一些安全/持久化设置加速(恢复完记得改回来):
SET GLOBAL innodb_flush_log_at_trx_commit = 2;
SET GLOBAL sync_binlog = 0;5.3 CSV 导入导出
导出为 CSV:
SELECT * FROM students
INTO OUTFILE '/var/lib/mysql-files/students.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n';这里有个必踩的坑:MySQL 有 secure_file_priv 限制,只允许往指定目录写文件。先查:
SHOW VARIABLES LIKE 'secure_file_priv';+------------------+-----------------------+
| Variable_name | Value |
+------------------+-----------------------+
| secure_file_priv | /var/lib/mysql-files/ |
+------------------+-----------------------+路径必须是这个目录(或它的子目录),否则报 ERROR 1290。
导入 CSV:
LOAD DATA INFILE '/var/lib/mysql-files/students.csv'
INTO TABLE students
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES; -- 跳过表头如果文件在客户端机器而不是服务器上,要用 LOAD DATA LOCAL INFILE,并且客户端和服务端都得开 local_infile:
mysql --local-infile=1 -u root -p school_db -e "LOAD DATA LOCAL INFILE 'students.csv' INTO TABLE students ..."local_infile 默认是关的,因为它有安全风险(恶意服务器可诱导客户端上传本地文件)。
5.4 mysqlimport:CSV 导入的另一条路
mysqlimport -u root -p --local --ignore-lines=1 \
--fields-terminated-by=',' school_db students.csvmysqlimport 要求 CSV 文件名(去扩展名)等于表名,它本质是 LOAD DATA 的封装。
六、配置
6.1 配置文件的位置与优先级
MySQL 按顺序读多个配置文件,后面的覆盖前面的:
/etc/my.cnf → /etc/mysql/my.cnf → $MYSQL_HOME/my.cnf → ~/.my.cnf~/.my.cnf 是用户级配置,优先级最高,适合放个人的连接默认值。[client] 段影响所有客户端,[mysqld] 段只影响服务器。
6.2 常见服务器参数
[mysqld]
datadir = /var/lib/mysql
socket = /var/run/mysqld/mysqld.sock
log-error = /var/log/mysql/error.log
# 性能相关
innodb_buffer_pool_size = 4G # InnoDB 缓冲池,建议物理内存的 50%-70%
max_connections = 200 # 最大连接数
innodb_log_file_size = 512M # 重做日志大小,影响写入性能
innodb_flush_log_at_trx_commit = 1 # 1=最安全(默认),2=更快但可能丢1秒数据MySQL 8.0 的重要变化:查询缓存(
query_cache_size)已被彻底移除。如果你从 5.7 配置抄来query_cache_size=128M,8.0 会启动失败或报未知变量。8.0 的性能优化重心是innodb_buffer_pool_size和索引,不再有查询缓存这一层。原文若照抄 5.7 配置,这是必须改掉的。
6.3 运行时查看与修改
-- 查看变量
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW VARIABLES LIKE 'character_set%';
-- 会话级修改(当前连接有效)
SET SESSION sql_mode = 'STRICT_TRANS_TABLES';
-- 全局修改(重启失效;写进配置文件才持久)
SET GLOBAL max_connections = 300;SET GLOBAL 改的是内存中的值,重启就丢。要持久化必须写进 my.cnf。MySQL 8 还支持 SET PERSIST(写进 mysqld-auto.cnf,重启保留):
SET PERSIST max_connections = 300;七、性能诊断
7.1 看执行计划
EXPLAIN SELECT * FROM students WHERE age > 18;
-- MySQL 8.0.18+ 可以看实际执行耗时
EXPLAIN ANALYZE SELECT * FROM students WHERE age > 18;重点看 type 列(ALL = 全表扫描,ref/range/const 依次更好)和 rows 列(预估扫描行数)。EXPLAIN ANALYZE 会真的执行并给出各步骤实际耗时,定位慢点比 EXPLAIN 准。
7.2 看当前在跑什么
SHOW PROCESSLIST; -- 简版:当前所有连接
SHOW FULL PROCESSLIST; -- 带完整 SQL 文本
-- 找出运行超过 10 秒的查询
SELECT id, user, time, state, LEFT(info, 80) AS sql_text
FROM information_schema.processlist
WHERE command != 'Sleep' AND time > 10
ORDER BY time DESC;7.3 看 InnoDB 内部状态
SHOW ENGINE INNODB STATUS\G这个输出信息量极大(锁等待、事务、缓冲池命中率、最近死锁)。排查锁问题、死锁时第一眼看它。
7.4 计数器与连接数
SHOW STATUS LIKE 'Threads_connected'; -- 当前连接数
SHOW STATUS LIKE 'Threads_running'; -- 正在执行的连接数(关键指标)
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';-- 缓冲池读命中
SHOW STATUS LIKE 'Com_select'; -- SELECT 总次数Threads_running 持续偏高,说明有慢查询堆积;Threads_connected 接近 max_connections 就该扩容或查连接泄漏了。
7.5 mysqladmin:命令行巡检
mysqladmin -u root -p status # 一行摘要:连接数/QPS/慢查询
mysqladmin -u root -p processlist # 等价 SHOW PROCESSLIST
mysqladmin -u root -p extended-status # 等价 SHOW STATUS
mysqladmin -u root -p variables # 等价 SHOW VARIABLES
mysqladmin -u root -p ping # 探活,脚本里用来判断服务是否存活八、常见问题处理
8.1 忘记 root 密码(MySQL 8 正确流程)
# 1. 停服务
sudo systemctl stop mysqld
# 2. 以跳过权限表 + 禁用网络 的方式启动(--skip-networking 是安全关键)
sudo mysqld_safe --skip-grant-tables --skip-networking &
# 3. 免密登录
mysql -u root-- 4. 在跳过权限的会话里,必须先刷新权限,ALTER USER 才可用
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';# 5. 关掉临时实例,正常启动
mysqladmin -u root -p shutdown
sudo systemctl start mysqld两个要点:--skip-networking 必须加(否则这段时间任何能连到端口的人都能免密进来);FLUSH PRIVILEGES 必须在 ALTER USER 之前(跳过权限表时权限表在内存里是空的)。
8.2 连接错误速查
| 错误码 | 含义 | 排查方向 |
|---|---|---|
1045 | Access denied | 用户名/密码错;或该用户不允许从当前主机连接 |
2002 | Can’t connect through socket | socket 路径不对,或服务没起 |
2003 | Can’t connect to server | 网络不通、端口没开、防火墙、bind-address 限制 |
1049 | Unknown database | 库名写错 |
1290 | secure_file_priv 限制 | 导出/导入路径不在允许目录内 |
1205 | Lock wait timeout | 有长事务持锁,查 SHOW ENGINE INNODB STATUS |
2003 最常见的隐性原因是 bind-address = 127.0.0.1(默认只监听本地),远程连不上时先去 my.cnf 看这一行。
8.3 导入很慢 / 中途锁表
- 大文件导入前先
SET GLOBAL innodb_flush_log_at_trx_commit = 2;(见 5.2) - 用
--single-transaction做备份,避免锁表影响线上 - 超大库(几十 GB 以上)别用
mysqldump,用mydumper/myloader(多线程)或物理备份工具xtrabackup
九、实用技巧
9.1 用 pager 翻看大结果集
\P less
SELECT * FROM big_table; -- 结果进入 less,可翻页、可搜索
\P -- 恢复默认输出9.2 常用 shell 别名
alias my='mysql --login-path=local'
alias mydump='mysqldump --single-transaction --routines --triggers'
alias myping='mysqladmin --login-path=local ping'9.3 定时备份脚本
#!/bin/bash
# /usr/local/bin/mysql-backup.sh
set -euo pipefail
BACKUP_DIR=/backups/mysql
mkdir -p "$BACKUP_DIR"
DATE=$(date +%F_%H%M)
mysqldump --login-path=local --single-transaction --routines --triggers \
--all-databases | gzip > "$BACKUP_DIR/all-$DATE.sql.gz"
# 只保留最近 7 天
find "$BACKUP_DIR" -name 'all-*.sql.gz' -mtime +7 -delete
echo "backup done: $BACKUP_DIR/all-$DATE.sql.gz"配合 cron:
# 每天凌晨 3 点备份
0 3 * * * /usr/local/bin/mysql-backup.sh >> /var/log/mysql-backup.log 2>&1附录:常用命令速查表
# —— 连接 ——
mysql -u user -p # 本地,交互输入密码
mysql --login-path=local # 用加密登录路径(推荐)
mysql -h host -P 3307 -u user -p db # 远程 + 指定库
# —— 非交互执行 ——
mysql -u u -p db -e "SQL" # 执行一条语句
mysql -u u -p db < file.sql # 执行脚本
mysql -B -N -u u -p db -e "SQL" > x.tsv # 批处理导出(便于脚本处理)
# —— 备份恢复 ——
mysqldump -u u -p --single-transaction --routines --triggers db > db.sql
mysqldump -u u -p --all-databases | gzip > all.sql.gz
mysql -u u -p db < db.sql
gunzip < all.sql.gz | mysql -u u -p
# —— 巡检 ——
mysqladmin -u u -p status
mysqladmin -u u -p processlist
mysqladmin -u u -p ping| 交互命令 | 作用 |
|---|---|
\G | 竖排输出 |
\s | 服务器状态 |
\u db | 切换数据库 |
"source f.sql" | 执行脚本 |
\P less | 分页器 |
"tee f.txt" | 输出同时写文件 |
\q | 退出 |
学习资源
- MySQL 8.0 官方文档 ——
mysql客户端选项见 “Client Programs” 章节 - MySQL Tutorial —— 入门教程
- MySQL 官方博客 —— 版本变更与性能话题,
query_cache移除等变化在这里有权威说明 - MySQL Workbench —— 图形化管理工具
mysql客户端值得记的就三类:连接(--login-path免密码)、批处理(-e/-B -N/<)、备份(--single-transaction)。其余选项用时mysql --help查一下就有。
参考&致谢
系列教程
数据库系列
- SQL 命令使用教程:从入门到精通 —— SQL 标准命令,含 MySQL/PostgreSQL/SQLite 方言对照
- SQLite 使用全面教程:轻量级数据库的终极指南 —— 嵌入式数据库,类型系统、外键陷阱、WAL、FTS5
- MySQL 命令行使用全面教程:从入门到精通 ——
mysql客户端工具,批处理、备份、性能诊断 - MySQL 使用全面指南:从入门到高级实践 —— MySQL 安装配置、字符集、索引、事务锁、复制
- PostgreSQL 使用全面指南:从入门到企业级应用 —— PG 认证配置、JSONB、分区、备份与高可用
- PostgreSQL 命令行使用教程:掌握 psql 工具 ——
psql元命令、脚本化、\copy与pg_dump - PostgreSQL 实现原理深度剖析:高性能数据库引擎的核心机制 —— MVCC、WAL、B-tree 内核机制与可验证观察方法

