连接阶段执行以下任务:
- 交换客户端和服务器的功能(capabilities)
- 如果需要,设置SSL通信通道
- 根据服务器验证客户端
5.1 初始化握手(Initial Handshake)
初始握手开始于服务器发送Initial Handshake Packet给客户端。
此后,可选地,客户端可以请求使用SSL Connection Request Packet建立SSL Connection Request Packet ,然后客户端发送Handshake Response Packet 。
5.1.1 普通握手
- 1.服务端发送初始化握手报文
- 2.客户端回复握手响应报文
5.1.2 SSL握手
1.服务器发送Initial Handshake Packet
2.客户端使用SSL Connection Request Packet回复
3.使用SSL交换导致建立SSL连接
4.客户端发送Handshake Response Packet
5.1.3 确定认证方式
认证用户的方法存储在mysql.user表的plugin列中。客户端的握手响应包中包含登录用户, 服务器使用握手响应包中的登录用户查找mysql.user表中的用户信息,并找到要使用的身份验证方法。
服务的在初始化握手包中使用了默认的身份认证方式,客户端可以选择是否使用该认证方式。如果客户端的认证方式和服务的认证方式不匹配,那么服务端使用Authentication Method Switch Request Packet报文通知客户端。
MySQL4.0的MySQL协议仅支持Old Password Authentication ,MySQL4.1中添加了Secure Password Authentication方法,而在MySQL5.5中,可以通过认证插件实现任意认证方式。
如果客户端或服务器不支持可插拔身份验证( CLIENT_PLUGIN_AUTH能力标志未设置),则使用的身份验证方法从客户端和服务器功能推断如下:
1.如果未设置CLIENT_PROTOCOL_41或CLIENT_SECURE_CONNECTION则使用的方法是Old Password Authentication 。
2.如果CLIENT_PROTOCOL_41和CLIENT_SECURE_CONNECTION都已设置但CLIENT_PLUGIN_AUTH未设置,则使用的方法是Secure Password Authentication 。
5.2 认证阶段
5.2.1 成功认证
成功的快速认证路径如下所示:
1.客户端连接到服务器
2.服务器使用auth方法以Initial Handshake Packet进行响应
3.客户端使用相同的auth方法发送Handshake Response Packet
4.客户端和服务器可能根据认证方法的要求交换进一步的数据包
5.服务器使用OK_Packet响应
注意:许多身份验证方法,包括本地mysql密码方法,由一个请求响应组成。 在这种情况下,在步骤4中不需要交换额外的数据包,服务器在接收到Handshake Response Packet后,客户端授权成功后,直接发送OK_Packet 。
5.2.2 验证失败
服务器通过发送ERR_Packet报文告诉客户端不允许进行连接。 这可能会在初次握手后的任何时刻发生。
1.客户端连接到服务器
2.服务器使用Initial Handshake Packet响应
3.客户端发送Handshake Response Packet
4.客户端和服务器可能根据所使用的认证方法的需要交换更多的数据包
5.服务器使用ERR_Packet进行响应并关闭连接
5.3 连接阶段的数据包
当客户端连接到服务器时,服务器向客户端发送握手包。
自从3.21.0版本是握手包使用HandshakeV10,从4.1开始握手响应包使用HandshakeResponse41
下面是列举HandshakeV10和HandshakeResponse41,ssl等其他报文略去
5.3.1 HandshakeV10
1 [0a] protocol version
string[NUL] server version
4 connection id
string[8] auth-plugin-data-part-1
1 [00] filler
2 capability flags (lower 2 bytes)
if more data in the packet:
1 character set
2 status flags
2 capability flags (upper 2 bytes)
if capabilities & CLIENT_PLUGIN_AUTH {
1 length of auth-plugin-data
} else {
1 [00]
}
string[10] reserved (all [00])
if capabilities & CLIENT_SECURE_CONNECTION {
string[$len] auth-plugin-data-part-2 ($len=MAX(13, length of auth-plugin-data - 8))
if capabilities & CLIENT_PLUGIN_AUTH {
string[NUL] auth-plugin name
}
字段详解:
1. protocol_version (1):值是0x0a,协议版本号
2. server_version (string.NUL): 服务器版本号,字符表示
3. connection_id (4):连接ID
4. auth_plugin_data_part_1 (string.fix_len):固定长度为8个字节
5. filler_1 (1):占位符,值为0x00
6. capability_flag_1 (2):能力标示,低字节2位
7. character_set (1):字符集合
8. status_flags (2):Protocol::StatusFlags (optional)
9. capability_flags_2 (2):能力标示,高字节2位
10. auth_plugin_data_len (1) :length of the combined auth_plugin_data, if auth_plugin_data_len is > 0
11. auth_plugin_name (string.NUL) :name of the auth_method that the auth_plugin_data belongs to
5.3.2 HandshakeResponse41
4 capability flags, CLIENT_PROTOCOL_41 always set
4 max-packet size
1 character set
string[23] reserved (all [0])
string[NUL] username
if capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA {
lenenc-int length of auth-response
string[n] auth-response
} else if capabilities & CLIENT_SECURE_CONNECTION {
1 length of auth-response
string[n] auth-response
} else {
string[NUL] auth-response
}
if capabilities & CLIENT_CONNECT_WITH_DB {
string[NUL] database
}
if capabilities & CLIENT_PLUGIN_AUTH {
string[NUL] auth plugin name
}
if capabilities & CLIENT_CONNECT_ATTRS {
lenenc-int length of all key-values
lenenc-str key
lenenc-str value
if-more data in 'length of all key-values', more keys and value pairs
}
字段详解:
1. capability_flags (4):客户端能力标示
max_packet_size (4) :客户端发给服务端最大命令包大小
character_set (1) :字符集
username (string.fix_len):用户名,使用字符集表示字符
auth-response (string.NUL):根据认证方法生成的认证数据(登录密码加密)
database (string.NUL) :初始数据库,使用字符集表示字符
auth plugin name (string.NUL):生成认证数据的认证方法名称,是个UTF-8字符串
mysql能力标示请参考:https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags