mysql连接生命周期-连接阶段

具体详细参考:dev.mysql.com/doc/dev/mys...

这个阶段是客户端连接到 MySQL 服务器的核心过程,涉及能力协商、安全通道建立和用户身份验证。

核心目标:​​ 建立一条安全、功能匹配、经过身份验证的客户端与服务器之间的通信通道。

连接阶段的主要任务:​

  1. 能力交换 (Capability Exchange):​ 客户端和服务器互相告知对方支持哪些功能和选项(如是否支持 SSL、是否支持认证插件、最大数据包大小等)。
  2. SSL 通信通道设置 (SSL Communication Setup - Optional):​ 如果客户端请求并且服务器支持,在此阶段建立一个加密的 SSL/TLS 通信通道。这发生在发送实际认证响应之前。
  3. 客户端身份验证 (Client Authentication):​ 服务器根据其用户账户系统(主要是 mysql.user 表)验证客户端提供的凭据(通常是用户名和密码)。

连接阶段流程详解:​

  1. 初始连接 (Client Connect):​

    • 客户端发起一个 TCP/IP(或 Unix Socket)连接到 MySQL 服务器。
  2. 服务器初始响应 (Server Initial Response):​

    • 选项 A (错误 ERR_Packet):​ 服务器可能立即返回一个 ERR_Packet(例如,服务器过载、连接数满、IP 被拒绝)。因为没有进行任何协商,这个错误包可能不包含标准的 SQL 状态码。连接立即终止。
    • 选项 B (初始握手包 Initial Handshake Packet / Protocol::Handshake):​ 这是正常流程的开始。服务器发送一个包含以下关键信息的包:
      • 协议版本:​ 服务器使用的协议版本号。
      • 服务器版本:​ MySQL 服务器版本字符串。
      • 连接 ID:​ 服务器分配给此连接的唯一标识符。
      • 随机挑战值 (Scramble):​ 一串随机字节,用于后续的认证过程(防止重放攻击)。
      • 服务器能力标志 (Server Capability Flags):​ 指示服务器支持的功能(如 CLIENT_SSL, CLIENT_PLUGIN_AUTH, CLIENT_SECURE_CONNECTION, CLIENT_PROTOCOL_41)。
      • 服务器字符集:​ 服务器默认字符集。
      • 服务器状态标志:​ 服务器当前状态。
      • 初始认证数据 (Authentication Payload):​ 基于服务器的默认认证插件 (default_auth_plugin) 生成的一段数据(例如,一个挑战值)。
      • 默认认证插件名称:​ 服务器默认使用的认证方法名称(如 caching_sha2_password, mysql_native_password)。
  3. 客户端响应 (Client Handshake Response):​

    • SSL 请求 (Protocol::SSLRequest - Optional):​ 如果客户端在服务器的能力标志中看到 CLIENT_SSL 被设置,并且它希望使用 SSL,它会先发送一个 Protocol::SSLRequest 包(包含客户端能力标志)。
    • SSL 通道建立 (Plain Handshake - If Requested):​ 如果上一步发送了 SSLRequest,客户端和服务器将执行标准的 SSL/TLS 握手过程,在 TCP 连接之上建立一个加密通道。后续所有通信都通过此加密通道进行。
    • 握手响应包 (Protocol::HandshakeResponse):​ 客户端发送此包,包含:
      • 客户端能力标志 (Client Capability Flags):​ 客户端实际使用的功能子集(是客户端能力与服务器在 Protocol::Handshake 中宣布的能力的交集)。
      • 最大数据包大小:​ 客户端能接收的最大包大小。
      • 客户端字符集:​ 客户端使用的字符集。
      • 用户名:​ 客户端尝试登录的用户名。
      • 认证响应数据 (Authentication Response):​ 客户端根据它认为决定 使用的认证方法对服务器发来的初始挑战值(和密码)进行计算后生成的一段数据(例如,密码的加盐哈希)。客户端决定使用的认证方法名称也会包含在此包中(可能与服务器默认方法不同!​)。
      • 数据库名称 (Optional):​ 如果客户端指定了默认数据库(且服务器能力支持)。
      • 其他信息:​ 如认证插件名称(如果客户端支持 CLIENT_PLUGIN_AUTH)。

认证阶段:核心挑战与流程

认证的核心是验证客户端是否知道与指定用户名对应的密码。难点在于服务器在收到 HandshakeResponse 之前并不知道客户端要登录哪个用户(mysql.user 表里的 plugin 列定义该用户的认证方法)。这导致了"乐观猜测 "和潜在的"认证方法不匹配"。

  • 能力协商 (Capability Negotiation):​ 通过交换能力标志 (CLIENT_PROTOCOL_41, CLIENT_SECURE_CONNECTION, CLIENT_PLUGIN_AUTH),客户端和服务器确定它们共同支持的最低协议版本和认证方式(旧密码认证、本地认证、插件认证)。
  • 确定认证方法 (Determining Authentication Method):​
    • 服务器在 Protocol::Handshake 中使用其默认认证插件 (default_auth_plugin) 生成初始挑战值。
    • 客户端在 Protocol::HandshakeResponse 中指定它决定使用 的认证方法(通常就是它从服务器 Handshake 中看到的默认方法)并生成对应的响应。
    • 服务器在收到 HandshakeResponse 中的用户名 后,才能查找 mysql.user 表,找到该用户账户实际配置的认证方法 (user.plugin)。
    • 此时可能出现不一致:
      • 服务器初始挑战使用的默认方法 (default_auth_plugin) != 用户实际配置的方法 (user.plugin)。
      • 客户端响应时使用的方法 != 用户实际配置的方法 (user.plugin)。

后续认证流程(基于匹配结果):​

  1. 快速认证路径 (Fast Path - 乐观猜测成功):​

    • 条件:​ 服务器 Handshake 使用的默认方法 (default_auth_plugin) 恰好等于 用户实际配置的方法 (user.plugin),并且 客户端在 HandshakeResponse正确使用了该方法(或者兼容方法)进行响应。
    • 流程:​
      • 客户端连接 -> 服务器发送 Protocol::Handshake -> (可选SSL) -> 客户端发送 Protocol::HandshakeResponse -> 服务器验证响应
      • 如果验证成功:​ 服务器直接发送 OK_Packet,连接建立成功,进入命令阶段。(对于像 mysql_native_password 这样的单步方法,这通常是最终结果)。
      • 如果验证失败:​ 服务器发送 ERR_Packet,连接终止。
      • 如果需要更多数据 (Multi-step Auth):​ 如果认证方法需要多轮交互(如 sha256_password 可能需要公钥加密交换),服务器会发送 Protocol::AuthMoreData 包(以 0x01 开头,区别于 ERR_Packet0xFF),客户端回复相应数据,直到服务器发送 OK_PacketERR_Packet
  2. 认证方法不匹配 (Authentication Method Mismatch - 最常见的问题场景):​

    • 触发条件:​ 服务器初始挑战使用的默认方法 (default_auth_plugin) 不等于 用户实际配置的方法 (user.plugin),或者 客户端在 HandshakeResponse 中使用的认证方法 不兼容 于用户实际配置的方法 (user.plugin)。
    • 服务器动作 (Protocol::AuthSwitchRequest):​ 服务器检测到不匹配后,立即向客户端发送一个 Protocol::AuthSwitchRequest 包,明确告诉客户端:
      • **auth_plugin_name:​ 它 必须**使用哪个认证插件/方法(即用户实际配置的 user.plugin)。
      • **auth_plugin_data:​ 该方法对应的新初始挑战值/数据**。
    • 客户端动作:​
      • 如果客户端认识并支持新方法:​ 它立即切换,使用指定的新方法和新挑战值(以及用户密码)计算一个新的认证响应,并发送一个 Protocol::AuthSwitchResponse 包给服务器。
      • 如果客户端不认识或不支持新方法:​ 它直接断开连接。
    • 后续流程:​AuthSwitchResponse 开始,认证流程按照新指定的认证方法 继续进行。可能需要多个 AuthMoreData / AuthSwitchResponse 回合,最终服务器发送 OK_Packet (成功) 或 ERR_Packet (失败)。
  3. 客户端能力不足 (Insufficient Client Capabilities - 服务器直接拒绝):​

    • 触发条件:​ 客户端不支持插件式认证 (CLIENT_PLUGIN_AUTH 标志未设置),但遇到以下情况之一:
      • 用户账户配置了非原生的认证方法(如 caching_sha2_password, authentication_ldap_sasl)。
      • 服务器 Handshake 中使用的默认方法 (default_auth_plugin) 与 Native Authentication 不兼容(不太常见)。
    • 服务器动作:​ 服务器在识别到客户端能力不足以处理所需的认证方法后(通常在解析 HandshakeResponse 能力标志或用户名后),直接发送 ERR_Packet 并关闭连接 。没有 AuthSwitchRequest 的机会。
  4. 特殊案例:非插件客户端 (Non-CLIENT_PLUGIN_AUTH Clients) 与旧密码认证切换:​

    • 场景:​ 一个支持 CLIENT_PROTOCOL_41CLIENT_SECURE_CONNECTION 但不支持 CLIENT_PLUGIN_AUTH 的"现代"客户端(如 MySQL 5.0 客户端)尝试连接一个配置为使用旧密码认证 (mysql_old_password) 的用户账户。
    • 服务器动作:​ 服务器发送一个特殊的 Protocol::OldAuthSwitchRequest 包(不包含新插件名,隐式要求切换到旧密码认证)。
    • 客户端动作:​ 客户端应使用旧密码认证算法 和服务器在初始 Handshake 中发送的随机挑战值重新计算密码哈希,并发送一个 Protocol::HandshakeResponse320 包(使用旧格式)。
    • 后续流程:​ 服务器验证旧哈希,回复 OK_PacketERR_Packet

连接阶段后的身份验证:COM_CHANGE_USER

  • 在命令阶段 (Command Phase),客户端可以发送 COM_CHANGE_USER 命令来切换当前连接使用的用户账户(无需断开重连)。
  • 流程:​ 类似于初始连接阶段:
    • 客户端发送 COM_CHANGE_USER 包(包含新用户名、新密码的认证响应(基于初始挑战值)、新数据库等)。
    • 服务器根据新用户名查找 mysql.user 表,找到该用户的实际认证方法 (user.plugin)。
    • 如果匹配或兼容:​ 服务器验证响应,发送 OK_Packet(成功)或 ERR_Packet(失败)。
    • 如果不匹配:​ 服务器发送 Protocol::AuthSwitchRequest(或 Protocol::OldAuthSwitchRequest),要求客户端切换到正确的认证方法并重新认证。后续流程与连接阶段相同(AuthSwitchResponse, AuthMoreData 等),最终 OK_PacketERR_Packet
  • 非插件客户端的限制:​ 非插件客户端只能切换到使用原生认证 (mysql_native_password) 或旧密码认证 (mysql_old_password) 的用户。如果需要切换的账户使用其他方法,服务器会直接拒绝(发送 ERR_Packet或客户端无法处理 AuthSwitchRequest)。

总结:​

MySQL 连接阶段是一个精心设计的协议,通过能力交换、SSL 协商和复杂的认证流程(包括乐观猜测和处理认证方法不匹配)来建立安全可靠的客户端-服务器连接。理解 Protocol::Handshake, Protocol::HandshakeResponse, Protocol::AuthSwitchRequest, Protocol::AuthSwitchResponse, ERR_PacketOK_Packet 这些核心数据包以及 CLIENT_PLUGIN_AUTH 等能力标志对于诊断连接和认证问题至关重要。COM_CHANGE_USER 复用连接阶段的机制实现了高效的会话内用户切换。

相关推荐
汪子熙5 小时前
HSQLDB 数据库锁获取失败深度解析
数据库·后端
无色海9 小时前
MySQL协议中的TLS实现
数据库
weixin_4180076010 小时前
SpringJPA统计数据库表行数及更新频率
数据库
2301_7672332210 小时前
怎么优化MySQL中的索引
数据库·mysql
无色海10 小时前
MySQL 压缩数据包详解
数据库
海尔辛10 小时前
防御性安全:数字取证
数据库·安全·数字取证
繢鴻11 小时前
数据库优化实战分享
数据库
Cachel wood12 小时前
后端开发:计算机网络、数据库常识
android·大数据·数据库·数据仓库·sql·计算机网络·mysql
暗离子跃迁12 小时前
达梦数据库单机部署dmhs同步复制(dm8->kafka)
linux·运维·数据库·分布式·学习·kafka·达梦数据库