加载中...

加载中...

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

MySQL 命令行

一、连接服务器

1.1 基础连接

mysql -u root -p                          # 本地连接,回车后输入密码
mysql -h 127.0.0.1 -P 3306 -u app -p      # 指定主机和端口
mysql -u root -p school_db                # 连接后直接进入 school_db

1.2 参数速查

参数含义示例
-u用户名-u app
-p提示输入密码-p(单独写,别紧跟密码)
-h主机地址-h db.example.com
-P端口(大写)-P 3307
-SUnix 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 不是有效写法——--htmlmysql 命令的选项,要放在连接参数区,不能跟在 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.sql

3.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.csv

mysqlimport 要求 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 连接错误速查

错误码含义排查方向
1045Access denied用户名/密码错;或该用户不允许从当前主机连接
2002Can’t connect through socketsocket 路径不对,或服务没起
2003Can’t connect to server网络不通、端口没开、防火墙、bind-address 限制
1049Unknown database库名写错
1290secure_file_priv 限制导出/导入路径不在允许目录内
1205Lock 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退出

学习资源

  1. MySQL 8.0 官方文档 —— mysql 客户端选项见 “Client Programs” 章节
  2. MySQL Tutorial —— 入门教程
  3. MySQL 官方博客 —— 版本变更与性能话题,query_cache 移除等变化在这里有权威说明
  4. MySQL Workbench —— 图形化管理工具

mysql 客户端值得记的就三类:连接--login-path 免密码)、批处理-e / -B -N / <)、备份--single-transaction)。其余选项用时 mysql --help 查一下就有。

参考&致谢

系列教程

全部文章RSS订阅

数据库系列


MySQL命令行使用全面教程:从入门到精通
发布于
2025年11月22日
许可协议。转载请注明来源
评论
数据加载中 ...
 上一篇

阅读全文

SQLite使用全面教程:轻量级数据库的终极指南
SQLite使用全面教程:轻量级数据库的终极指南 SQLite使用全面教程:轻量级数据库的终极指南
SQLite 是部署量最大的数据库引擎,从手机 App 到浏览器内核都有它的身影。本文从安装和命令行讲起,逐步覆盖类型系统、外键约束、事务与 WAL、备份恢复和 Python 集成,重点说清那些容易踩的默认值陷阱。
2025-11-22
下一篇 

阅读全文

PostgreSQL命令行使用教程:掌握 psql 工具
PostgreSQL命令行使用教程:掌握 psql 工具 PostgreSQL命令行使用教程:掌握 psql 工具
psql 是 PostgreSQL 官方命令行客户端,也是最能体现 PG 风格的入口。它的元命令系统(\\d 家族、\\x、\\gset、\\copy)比多数数据库的命令行工具都好用,值得花时间熟悉。本文从连接讲起,覆盖元命令、脚本化、导入
2025-11-22