MySQL执行SQL最少需3次网络通信轮次:第一次为握手包与认证响应,第二次为Query命令与轻量响应,第三次起为结果集分片传输;TCP三次握手不计入MySQL协议通信。

MySQL 执行一条 SQL 语句,从连接建立到结果返回,最少需要 3 次网络通信轮次(request-response cycle),但实际中几乎总是 4 次或更多,取决于是否复用连接、是否触发认证重协商、是否分页返回等。关键不在于“次数”本身,而在于每次通信背后承担的协议职责。
TCP 三次握手不是 MySQL 协议通信,但它是所有后续通信的前提
很多人把 TCP 三次握手(SYN → SYN-ACK → ACK)误算作“MySQL 的一次通信”。它确实是建立链路的必要步骤,但属于操作系统内核层,MySQL 协议尚未启动。真正由 MySQL 客户端/服务端主导的、携带业务语义的通信,始于握手包(Handshake Initial Packet)。
第一次通信:MySQL 握手包(Handshake V10) + 认证响应
客户端收到 TCP 连接就绪信号后,立即收到服务端发来的 HandshakeV10 包,含 protocol version、server version、auth-plugin-data(随机 salt)等。客户端据此生成加密认证凭据,打包为 Handshake Response 发回 —— 这是一次完整的 request-response。若密码错误,服务端在此轮直接返回 Access denied for user 错误,不再继续。
- 典型错误现象:
Access denied for user 'xxx'@'xxx'就发生在这轮,说明认证失败,没走到 SQL 解析阶段 - 如果启用了
caching_sha2_password且客户端不支持,可能触发额外一轮Auth Switch Request/Response,变成 2 次认证通信 - 使用 Unix Socket 连接时,跳过 TCP 握手,但
HandshakeV10+ 响应仍必存在
第二次通信:Query 命令发送与 OK/Err 响应
认证成功后,客户端将原始 SQL 文本(如 SELECT * FROM users WHERE id = 1)封装进 COM_QUERY 包发出。服务端解析语法、查权限、生成执行计划,然后返回一个轻量级响应:可能是 OK_Packet(无结果集,如 INSERT)、ERR_Packet(语法错/权限不足),或 ResultSet Header(表示接下来要发数据行)。
- 注意:
SELECT不会在这次返回数据,只返回元信息(列数、类型等) - 如果 SQL 触发查询缓存(已默认禁用),且命中,服务端可能跳过优化器直接返回缓存结果 —— 但仍需按协议格式发
ResultSet Header+ 数据包,通信轮次不变 - 长连接下,这轮是唯一必须的 SQL 执行通信;短连接则每次都要重走前两轮
第三次及后续通信:结果集分片传输(Result Set Streaming)
对 SELECT 类查询,服务端不会把全部结果塞进一个 TCP 包。它按 net_buffer_length(默认 16KB)切块,每块封装为一个或多个 Text Resultset Row 包,逐个发给客户端。客户端收到每个包就解析一行(或一批),直到收到 EofPacket 或 OK_Packet 表示结束。
- 结果行数多时,这轮通信可能持续数十甚至数百次(比如查 10 万行,每包 200 行 → 至少 500 次)
- 客户端可通过设置
max_allowed_packet影响单包大小,但不能消除分片本质 - 使用游标(
DECLARE cur CURSOR FOR ...)或FETCH时,每次FETCH都是一次独立的COM_STMT_FETCH请求,对应新通信轮次
真实链路里最容易被忽略的,是「连接复用」和「认证上下文」的耦合关系:只要连接没断,HandshakeV10 和认证就只发生一次;但每次 COM_QUERY 都是独立请求,而结果传输又完全异步分片。所谓“一次 SQL 一次往返”,只是 HTTP 式的错觉 —— MySQL 协议是典型的流式、多段式交互。


















