news 2026/9/5 6:54:25

深入 MySQL 网络通信:客户端如何与服务端建立连接?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入 MySQL 网络通信:客户端如何与服务端建立连接?

导言

摘要:本文通过 tcpdump 抓包,完整拆解了从执行mysql命令到出现mysql>提示符的整个过程。内容涵盖 MySQL 的 TCP/IP 与 Unix Socket 两种通信方式、mysqld的启动监听、TCP 三次握手、MySQL 握手初始化包与认证包的字段解析、协议分包格式,以及caching_sha2_password认证插件的原理与线程模型,帮助读者从底层理解 MySQL 连接建立的每一步。

当你在终端执行mysql -h <数据库ip> -P 3306 -uroot -p时,输入密码,从客户端敲下回车,到最终出现mysql>提示符,这中间发生了什么?

MySQL 是典型的客户端/服务端(CS)架构,因此本质还是客户端发请求 -> 服务器处理 -> 返回结果集,类似于浏览器访问网站的流程。 不同的是MySQL走的是一套私有二进制协议,不是HTTP协议,也不是纯文本)。

一、MySQL 通信传输方式

传输方式说明典型场景
TCP/IP默认3306端口,跨主机访问mysql -h <MySQL主机ip> -P 3306
Unix Socket本机通信通常比 TCP/IP 更省网络协议栈开销mysql -uroot -p(默认连本机 socket)

二、mysqld 启动与监听

mysqld是 MySQL Server进程。启动之后,它需要告诉操作系统。

“如果有人想通过 TCP 连接 MySQL 进程监听的端口(默认3306),请把连接交给我。”

于是mysqld通过socket()系统调用让操作系统内核创建一个 Socket,然后通过bind()将其绑定到指定的监听地址和端口(默认通常为 3306),然后调用listen()将其设置为监听状态。这个 Socket 称为listening socket,它主要负责接收新的客户端连接请求,而不负责某个客户端建立连接后的实际数据传输。

三、MySQL 连接流程

整个流程可以用tcpdump抓包来窥见

#本机连远程 MySQL 时,抓本机发往 3306 端口的包 sudo tcpdump -i any -s 0 -A 'tcp port 3306' -w mysql_handshake.pcap
# 另一窗口执行 mysql -h <mysql服务器ip> -P 3306 -u你的用户 -p
tcpdump -nn -r mysql_handshake.pcap 用来读取抓包内容。 tcpdump -nn -X -r mysql_handshake.pcap 用于看 TCP Payload tcpdump -nn -A -r mysql_handshake.pcap 以 ASCII 形式查看 Payload

1. TCP 三次握手

客户端执行:

mysql -h <mysql服务器ip> -P 3306 -uroot -p

整个连接流程就开始了。


客户端发起连接后,TCP 三次握手实际由操作系统内核的 TCP/IP 协议栈负责处理。

当第一个 SYN 包到达时,内核会创建用于记录和管理该连接请求的request_sock对象(这里需要注意,request_sock并不是最终用于传输数据的 connected socket,而是内核在连接建立过程中用于管理连接请求的请求对象),这个对象主要用来保存客户端IP、客户端端口、服务器 IP、服务器端口、初始序列号、TCP Options等信息,可以简单理解成:

有人想和我建立 TCP 连接,我先把这个人的信息记下来

然后将其放入 SYN Queue(半连接队列)。然后服务器不会傻等客户端,会回复SYN+ACK,大概意思就是:

我收到了你的 SYN,我也同意建立连接,这是我的初始序列号

等客户端回复ACK后,这个ACK会触发内核把该连接从 SYN Queue(半连接队列)中移除,并创建对应的connected socket,然后将该连接放入 Accept Queue(已完成连接队列)。这里需要注意与负责接收新连接的listening socket不同,connected socket专门负责与某一个客户端进行双向数据传输,例如接收 MySQL 协议数据、SQL 请求,以及向客户端发送结果集、错误信息等。

mysqld调用accept()时,内核会从 Accept Queue 中取出一个已经建立的连接,并为mysqld创建一个新的文件描述符FD,这个 FD 指向内核中对应的connected socket

当客户端连接关闭并完成相关资源回收后,对应的connected socket和文件描述符等资源会被释放,而listening socket仍然保持监听状态,可以继续通过accept()接收新的客户端连接。TCP 连接建立之后,MySQL 协议才会在这个连接之上继续进行 Initial Handshake、身份认证以及后续的 SQL 通信。

三次握手是操作系统网络协议栈层要做的事,MySQL自己不管。客户端connect()时内核自动完成 TCP握手过程。

此外我们还可以通过tcpdump抓包看到tcp三次握手的完整过程。

22:34:55.736318 IP 192.168.255.10.58537 > 203.0.113.5.3306: Flags [S], seq 940091726, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 510555173 ecr 0,sackOK,eol], length 0 22:34:55.736637 IP 203.0.113.5.3306 > 192.168.255.10.58537: Flags [S.], seq 965481546, ack 940091727, win 65535, options [mss 16344,nop,nop,TS val 971023692 ecr 510555173,nop,wscale 5], length 0 22:34:55.736730 IP 192.168.255.10.58537 > 203.0.113.5.3306: Flags [.], ack 1, win 6380, options [nop,nop,TS val 510555173 ecr 971023692], length 0
22:34:55.736318 客户端 58537 > 服务器 3306: [S] ← SYN,我要连你 22:34:55.736637 服务器 3306 > 客户端 58537: [S.] ← SYN+ACK,我同意 22:34:55.736730 客户端 58537 > 服务器 3306: [.] ← ACK,那我开始发数据

length=0 表明 tcp payload = 0 字节、 Flags表示标志(syn、ack等),seq表示序列号,win表明自己接受窗口大小

2. MySQL 握手流程

TCP 建立之后,才进入MySQL协议。接下来mysqld会给客户端发送MySQL Initial Handshake Packet

2.1 服务器 -> 客户端:握手初始化包

首先我们通过tcpdump工具可以查看到底层的字节信息
服务器发来第一个数据包length 78,这是 MySQL 的握手初始化包

22:34:56.058254 IP 203.0.113.5.3306 > 192.168.255.10.58537: Flags [P.], seq 1:79, ack 1, win 32768, options [nop,nop,TS val 971024014 ecr 510555173], length 78 0x0000: 4500 0082 3e22 0000 ff06 bfda 0986 f43f E...>".........? 0x0010: c0a8 ff0a 0cea e4a9 398c 144b 3808 a94f ........9..K8..O 0x0020: 8018 8000 b565 0000 0101 080a 39e0 a68e .....e......9... 0x0030: 1e6e 7425 4a00 0000 0a32 362e 372e 3000 .nt%J....26.7.0. 0x0040: ca2a 0000 3201 586b 7c1d 0242 00ff ffff .*..2.Xk|..B.... 0x0050: 0200 ffdf 1500 0000 0000 0000 0000 000a ................ 0x0060: 2558 5112 5a5e 4a1a 4a70 3a00 6361 6368 %XQ.Z^J.Jp:.cach 0x0070: 696e 675f 7368 6132 5f70 6173 7377 6f72 ing_sha2_passwor 0x0080: 6400

这是mysql向客户端打招呼的包,首先看4a 00 00这是MySQL包头:长度 0x4a 序号0
后面紧跟74字节的payload,内容就是在告诉客户端 “这是我的协议版本、服务器版本和随机盐,插件认证请用caching_sha2_password认证”。

我们通过tcpdump解读MySQL Initial Handshake Packet,可以获得它的结构。

字段长度含义
protocol_version1固定0x0A(协议版本 10)
server_version变长(NULL 结尾)8.0.38
connection_id4线程 ID,即SHOW PROCESSLIST里的 Id
auth-plugin-data-part-18salt 前半(随机数)
filler1固定0x00
capability_flags(低 16 位)2服务器能力标志低位
character_set1默认字符集编号
status_flags2状态标志
capability_flags(高 16 位)2能力标志高位
auth_plugin_data_len1salt 总长度
reserved10保留,全 0
auth-plugin-data-part-2变长salt 后半
auth_plugin_name变长(NUL 结尾)认证插件名,如caching_sha2_password
22:34:56.058767 IP 192.168.255.10.58537 > 203.0.113.5.3306: Flags [P.], seq 1:37, ack 79, win 6379, options [nop,nop,TS val 510555495 ecr 971024014], length 36 0x0000: 4500 0058 0000 4000 4006 7d27 c0a8 ff0a E..X..@.@.}'.... 0x0010: 0986 f43f e4a9 0cea 3808 a94f 398c 1499 ...?....8..O9... 0x0020: 8018 18eb 87cd 0000 0101 080a 1e6e 7567 .............nug 0x0030: 39e0 a68e 2000 0001 a5ae be19 0000 0040 9..............@ 0x0040: ff00 0000 0000 0000 0000 0000 0000 0000 ................ 0x0050: 0000 0000 0000 0000 ........

然后比较有意思的就是 客户端并没有直接回复,而是发起36字节的SSLRequest,这是属于MySQL协议层,相当于客户端在说“我要用SSL加密”(可以看见包里带MySQL包头)。

之后进入TLS握手阶段,客户端发起ClientHello,这是纯TLS记录,里面包含客户端支持的加密套件编号。接着到了最值得注意的地方了,服务器一口气回了2227B的大包,里面包含了服务器选定的加密套件、服务器证书,以及通知客户端我要开始加密了

2.2 客户端 -> 服务器: 认证包

紧接着,客户端回复,宣布我也切加密了,以及加密的应用数据,其实就是客户端回复MySQL的认证包HandshakeResponse41 ,也就是用户名、加密后的密码。但因为TLS已经建立,这些内容被加密了,所以在抓包里你看到的是一堆随机字节(56 29 71 6a 17 c2 95 …),完全看不到明文用户名和密码。

包里的字段如下

字段含义
capability_flags客户端能力标志(与服务器取交集)
max_packet_size客户端能收的最大包
character_set客户端字符集
username用户名
auth_response密码加密结果(用 salt 算出的)
database要连接的默认库(可选)
auth_plugin_name客户端确认使用的插件

客户端获取到认证插件后,用它和salt进行计算得到auth_response,用于MySQL服务端加密计算后得到的结果进行比对,如果相等,说明验证正确

除此之外,capability_flags是比较重要的字段,它告诉服务端我支持哪些 MySQL 协议能力。而且之前初始化握手包,也有capability_flags,那么双方连接能够使用的能力就是二者的交集。主要是用于这样的场景:服务器可能支持很多新功能,但老客户端并不认识,所以服务器不能直接说:

“我所有功能都打开,你自己看着办。”

所以通过capability_flags协调双方都支持的功能。

2.3 服务器 -> 客户端:OK 包 或 ERR 包

接下来比较简单,就是服务器对于客户端身份认证的回复。

认证成功 ->OK包(首字节0x00),随后进入命令循环。

失败 ->ERR包(首字节0xFF),带错误码和消息。

四、MySQL 协议分包格式

刚才分析字节流就注意到MySQL协议包,每个包都是4 字节包头、payload

  • 前 3 字节:payload 长度(受max_allowed_packet限制)
  • 第 4 字节:序号(sequence id,保证有序)
  • 后面:命令类型 + 参数

在命令阶段,客户端发送的 MySQL Command Packet 的 Payload 第一个字节是命令类型,例如0x03表示COM_QUERY0x16表示COM_STMT_PREPARE0x17表示COM_STMT_EXECUTE0x01表示COM_QUITSHOW PROCESSLIST中的Command则是服务器对当前连接所处命令/状态的展示,不能简单等同于这些操作码。

还有一点需要注意就是当payload超过16MB时,MySQL 协议会自动拆分为多个包,每个包的序号递增
至于为什么是16MB?那是 payload 长度是由3个字节决定的,所以2的24 次方=16777216,约等于16MB

五、caching_sha2_password的补充:

如果没走 SSL,客户端没拿到 RSA 公钥,服务器会发一个AuthMoreData包要求客户端拿公钥加密密码再发一次

1. 为什么要换掉 mysql_native_password

mysql_native_password用的是SHA1。SHA1 早在 2017 年就被 Google 和 CWI 用碰撞攻击实际攻破了(SHAttered 攻击),虽然那针对的是文件碰撞、不直接影响密码,但安全界共识是SHA1 该退役了。所以 8.0 全面换成SHA256系列,默认就是caching_sha2_password

2. 服务器端到底存的是什么

mysql.user

SELECT user, host, plugin, authentication_string FROM mysql.user;

authentication_string里存的不是明文,也不是单纯 SHA256(密码),而是:SHA256+盐+5000轮迭代

caching_sha2_password的"caching"指的是另一个东西,Server 内存里维护一份auth cache,第一次完整认证(走 SSL 或 RSA)通过后,把(user, host, hash)三元组记下来;下次同一用户再连,客户端只需发scramble,服务端在内存缓存里直接比对,跳过昂贵的 RSA 交换。

六、连接管理与线程模型

TCP 通了,服务器接下来要解决的问题是:这条连接由谁来伺候?(认证还需要线程来帮忙处理)

MySQL的答案很朴素,每个客户端连接分配一个专属线程,从此这个线程就和这条连接绑定,直到连接断开。这就是经典的"一连接一线程"(thread-per-connection)模型,也是社区版MySQL的模型。连接断开后,线程退出或被线程缓存复用。

相关的重要命令有下面这些

SHOW VARIABLES LIKE 'thread_cache_size'; -- 缓存最多留多少个空闲线程 SHOW STATUS LIKE 'Threads_%'; -- Threads_cached 缓存里现在有几个空线程 -- Threads_connected 当前活跃连接数 -- Threads_created 自启动以来一共创建过多少线程(重点看这个) -- Threads_running 正在跑 SQL 的线程数

如果Threads_created增长很快(比如每分钟涨几百),说明thread_cache_size偏小、连接复用没吃到红利,需要调大或者上层用连接池。

从客户端 SYN 到进入 MySQL 认证阶段,有三道容量闸门,任何一道爆了都会导致"连不上":

  • 一个就是Accept Queue上限,队列满时新 SYN 会被丢弃
  • max_connections,全服务器允许的最大并发连接,超过就报Too many connections
  • max_user_connections 单个账号最多能同时开几条连接

查看当前情况:

SHOW VARIABLES LIKE 'max_connections'; SHOW STATUS LIKE 'Max_used_connections'; -- 启动以来的峰值 SHOW STATUS LIKE 'Connection_errors_%'; -- 各类连接错误计数

还有最后一点是关于权限的东西要讲——关于权限

权限是在认证时一次性从mysql.usermysql.db等表读入内存,并附着在这条连接的线程上下文里。

GRANT、REVOKE后,已存在的连接仍然持有认证时获得的权限快照,只有新连接或 KILL 后重连才会读取最新权限。FLUSH PRIVILEGES 只影响新建立的连接,对现有连接无效。

结尾

以上就是客户端发起连接到MySQL服务端连接的全流程

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 10:07:51

5个吾爱热门排行榜的小工具,简直吹爆!

嗨&#xff0c;今天给大家分享几个有意思的吾爱热门小工具。虽然算不上多牛逼&#xff0c;但在某些关键时刻还真就只有这些工具能够满足你的需求。首先是电脑手机文件互传工具&#xff0c;大小还不到 0.8MB。大多数人都习惯用微信或 QQ 来传输文件&#xff0c;但有了这款小工具…

作者头像 李华
网站建设 2026/9/5 8:12:22

生产级Agent落地的五大工程规则与排查指南

把能跑的 Agent Demo 变成能长期承受生产压力的 Agent&#xff0c;真正的难点不是模型推理&#xff0c;而是边界控制、失败兜底、可观测性和权限设计。很多 Agent 项目在本地示例里表现很好&#xff0c;一接到真实业务就出现“执行器不响应”“工具调用结果没有被模型采用”“批…

作者头像 李华
网站建设 2026/9/4 16:25:14

多窗口RTSP拉流工具实战:基于Python+OpenCV的独立解码与断线重连

简介&#xff1a;一款支持多窗口并发拉流的实时流播放工具&#xff0c;面向视频监控值守人员、安防集成商与流媒体开发者。它可在单一界面同时打开多个窗口&#xff0c;独立拉取不同摄像头的实时视频&#xff0c;并自由切换一比一、一比二、二乘四等布局&#xff0c;避免为每路…

作者头像 李华
网站建设 2026/9/4 9:52:29

Agent模块化管理实践:从单体脚本到积木式编排开发指南

Agent 开发正在经历一次明显的转变&#xff1a;从“写一个大 Prompt 加几个工具调用”转向“把能力拆成模块&#xff0c;再像搭积木一样编排起来”。Hermes Studio 正在开发 Agent 模块化管理&#xff0c;恰好切在这个方向上。这意味着 Agent 的对话、工具、记忆、技能会被拆成…

作者头像 李华
网站建设 2026/9/4 9:10:02

C8051F350称重系统设计:24位ADC信号链与标定实战

简介&#xff1a;面向单片机与工业计量领域开发者的C8051F350称重系统设计资源&#xff0c;以C8051F350混合信号MCU为核心&#xff0c;完整覆盖从重量传感器模拟信号采集、ADC转换、数字滤波到重量计算与输出的实现流程&#xff0c;适合需要快速搭建高精度、低功耗称重方案的嵌…

作者头像 李华