mysql lane decodes the MySQL client/server protocol: the SQL a client sends over COM_QUERY, the statements behind every prepared-statement id, and the result sets the server returns in both the text and the binary encoding.
config.yaml
What the codec reads
A MySQL byte means different things depending on what the handshake negotiated and on the command in flight, where a pgwire message declares its own type and length. The codec tracks both, one instance per connection, across both directions:- Capabilities. The codec latches the negotiated set from the client’s handshake response.
CLIENT_DEPRECATE_EOFalone decides whether a result set ends with an EOF packet or an OK packet that begins with the same byte. - Prepared statements.
COM_STMT_EXECUTEcarries no SQL, only the numeric id the server assigned in its reply toCOM_STMT_PREPARE. The codec keeps that map and attributes each execute to its text, which is the path ORMs take. - Multi-statements. Connector/J and most ORMs negotiate
CLIENT_MULTI_STATEMENTSby default, soSELECT 1; DROP TABLE usersarrives as oneCOM_QUERY. The codec splits it with MySQL’s own lexical rules (backtick identifiers,#comments, backslash escapes) before classifying, so a statement hidden after a string literal cannot ride through under aselectclassification.
What it refuses
Three negotiated features would make later bytes unreadable, and the codec refuses the stream instead of forwarding what it cannot inspect. Each refusal closes the connection with an operator-facing reason:
A codec that forwards what it cannot parse turns into a bypass: the session works, no policy runs, the audit trail records nothing, and the gap stays invisible until an audit finds it. A refusal surfaces one clear error at the moment of the negotiation.
TLS on each leg
MySQL negotiates TLS in-band, and unlike pgwire the server greets first: the client’s upgrade request is a truncated handshake response rather than a self-describing packet. The lane terminates neither side of that exchange:
Both hops carry the protocol in the clear by design, so keep them where that is acceptable: loopback, a unix socket, one pod, or a network a NetworkPolicy narrows. The Transport section covers the boundary each choice draws.
Masking
The codec re-frames result sets in both encodings, because the two share nothing:- Text protocol rows are length-encoded strings, and the codec rewrites them value by value.
- Binary protocol rows, the encoding prepared statements return, carry a NULL bitmap and type-driven values. The codec rewrites string-typed columns and leaves a numeric column alone rather than corrupting it.
NULL survives masking as a NULL: re-encoding it as an empty string would turn “no value” into “the empty string” and change what the client computes. Column rules match the names the server declared in the result set’s column definitions.
Denials
A denied statement returns a nativeERR_Packet, and the session stays usable afterwards:
The Envoy lane
Envoy’s MySQL filter parses no SQL, so the lane is plaintcp_proxy, same shape as the Postgres one with the cluster pointed at the mysql listener’s port:
envoy.yaml
Next
Config File Reference
Every listener field, inheritance between lanes, and what startup refuses.
Data Masking
Strategies, entity types, and the column-versus-detection tradeoff.