服务器启动后,会使用TCP 监听一个本地接口,当客户端连接请求到达,就会执行三段握手以及 Mysql 的权限验证,验证成功后。客户端会开始发送请求,服务器会以相应的报文格式分会数据。
当客户端发送完成后,会发送特殊报文,告知服务器结束会话。
https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake
https://www.cnblogs.com/davygeek/p/5647175.html

1. 连接过程

详细说明一下 MYSQL 客户端与服务器之间的交互,主要分为两部分,握手认证阶段和命令执行阶段

  1. 三次握手建立 TCP 连接。
  2. 建立 MySQL 连接,也就是认证阶段。
    服务端 -> 客户端:发送握手初始化包 (Handshake Initialization Packet)。
    客户端 -> 服务端:发送验证包 (Client Authentication Packet)。
    服务端 -> 客户端:认证结果消息。

image.png

  1. 认证通过之后,客户端开始与服务端之间交互,也就是命令执行阶段。
    客户端 -> 服务端:发送命令包 (Command Packet)。
    服务端 -> 客户端:发送回应包 (OK Packet, or Error Packet, or Result Set Packet)。

image.png

  1. 断开 MySQL 连接。
    客户端 -> 服务器:发送退出命令包。
  2. 四次握手断开 TCP 连接。

从服务端发给客户端的包有四种:数据包,数据结束包,成功报告包,错误消息包
从客户端发给服务端的包有两种:登录时的 auth 包,执行 sql 的 cmd 包

2. 报文格式:

  1. +-------------------+--------------+---------------------------------------------------+
  2. | 3 Bytes | 1 Byte | N Bytes |
  3. +-------------------+--------------+---------------------------------------------------+
  4. |<= length of msg =>|<= sequence =>|<==================== data =======================>|
  5. |<============= header ===========>|<==================== body =======================>|

包含内容:

  1. 报文长度,标记当前请求的实际数据长度,以字节为单位。
  2. 序号,保证交互时报文的顺序。

    2.1 客户端请求报文:

    从客户端发到服务端的请求命令:
    1. +-------------------+------------------------------------------------------------------+
    2. | 1 Bytes | N Bytes |
    3. +-------------------+------------------------------------------------------------------+
    4. |<==== command ====>|<============================ arguments =========================>|
    第一个标识符:标明当前请求消息的类型,是切换数据库,还是查询命令等
    而 argument 是指用户在 Mysql 客户端输入的命令,不包括分号:
    1. // 输入 mysql
    2. // 请求数据报文
    3. use mysql;
    4. 0x20 0x6d 0x79 0x73 0x71 0x6c
    5. 请求类型 指令的 ascii

    2.2 登录初始化报文

    服务端 ->客户端的 握手初始化报文
    20190412194902719.png
  • 协议版本号:服务器所使用的MySQL协议版本号
  • 服务器线程:服务端为此客户端创建的线程ID
  • 挑战随机数:MySQL数据库用户认证采用的是挑战/应答的方式,服务器生成该挑战数并发送给客户端,由客户端进行处理并返回相应结果,然后服务器检查是否与预期的结果相同,从而完成用户认证的过程。

image.png

2.3 登录认证报文(客户端 -> 服务器)2019041220052139.png

  1. 客户端权能标志:客户端收到服务器发来的初始化报文后,会对服务器发送的权能标志进行修改,保留自身所支持的功能,然后将权能标返回给服务器,从而保证服务器与客户端通讯的兼容性。
  2. 消息长度:客户端发送请求时所支持的最大消息长度值
  3. 字符编码:表示通讯过程中使用的字符编码,与服务器在认证报文中发送的相同
  4. 用户名:客户端登陆的用户名
  5. 挑战认证数据:客户端用户密码使用服务器发送的挑战随机数进行加密后,生成挑战认证数据,返回给服务器用于服务端的认证

image.png

2.4 认证结果报文:

服务端进行验证,用户名,密码是否正确,正确返回 OK 报文,不正确返回 ERROR 报文
我们可以看下 mysql 中 user 表部分,这里如果需要登录,那么 host, user, account_locked 部分需要结合来看,缺一不可。参考 https://dev.mysql.com/doc/refman/8.0/en/connection-access.html
image.pngimage.png
这里我登陆的是 root 账号,可以看到,auth_string非空,并且 account_locked 为 n,故此时可正常登录。
再创建一个 User: usr = testuser, pwd = ‘123’
image.png
虽然权限减少了,但是 host , user ,account_locked = n , 也存在authentication_String 非空。

3. 具体过程:

  • 先三次握手,进行物理机连接,服务器启动后一直监听 tcp 端口

v2-1587e91f14923eae0fa7d846cb10df99_720w.jpg

  • 握手认证

image.png

  • 命令执行
  • 四次挥手断开连接v2-6e5f05603526c1d259b300f20b8857a5_720w.jpg