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 changes meaning with the negotiated capabilities and the command that produced the reply. The codec keeps one connection state across both directions.- Capabilities. The client’s handshake response decides whether result sets end with EOF or OK packets and whether the packet framing remains inspectable.
- Command order. Clients pipeline commands. The codec pairs each reply
with a FIFO entry, while skipping commands such as
COM_STMT_CLOSEthat have no reply. - Multi-statements. Connector/J and many ORMs send
SELECT 1; DROP TABLE usersas oneCOM_QUERY. The MySQL lexer handles backtick identifiers,#comments and backslash escapes before the codec classifies each statement.
Prepared statements and cursors
COM_STMT_EXECUTE carries a numeric statement id instead of SQL. The codec
records the text from COM_STMT_PREPARE and uses it for policy and audit when
the client executes that id.
A server-side cursor returns column definitions when it opens, then sends
binary rows through COM_STMT_FETCH without repeating those definitions. The
codec retains one metadata copy for inspection and one for masking. It removes
each copy after its walker passes the fetch that preceded COM_STMT_CLOSE or
COM_STMT_RESET, even when the fetch lacks SERVER_STATUS_LAST_ROW_SENT.
The codec refuses a fetch when it did not observe the cursor open. Forwarding
such rows would leave column-based masking with no column names.
What it refuses
Several protocol features replace the framing or metadata the codec needs. The lane closes the connection when a client negotiates one:
The codec closes the connection before opaque bytes reach the database. If it
forwarded them, policy and audit would lose visibility without reporting the
gap.
TLS on each leg
MySQL sends its greeting before either peer can request TLS. The client and database legs use separate settings.
Use
--ssl-mode=DISABLED for a client command that must work with either
upstream mode.
The lane removes CLIENT_SSL from the client greeting when upstream_tls is
configured. A client using --ssl-mode=PREFERRED continues in plaintext.
--ssl-mode=REQUIRED stops because the client-facing connection does not
offer TLS.
The lane handles the server-facing exchange itself when upstream_tls is
present. It reads the greeting, sends a MySQL SSLRequest, verifies the
certificate, and completes authentication inside TLS. The lane closes the
connection when the server omits TLS support, certificate verification fails,
or the handshake fails. It does not downgrade to plaintext.
RSA authentication on the client leg
MySQL clients usingcaching_sha2_password or sha256_password encrypt the
password when the connection has no TLS. They choose one of two key flows:
- A client with no saved key asks the lane for one. The lane generates an ephemeral key, decrypts the response, and sends the recovered password inside the verified upstream TLS connection.
- A client with a saved key skips that request and sends ciphertext at once.
Set
mysql_auth_key_fileto a stable RSA private key, then give the public half to the client.
mysql-auth.key into the Sidecar and keep it out of client containers.
Mount mysql-auth.pub into clients that pin the key. The MySQL CLI uses
--server-public-key-path:
1045 (28000) and the Sidecar does not forward the ciphertext.
The
MySQL example stack
generates this key pair, mounts each half on the correct side, and runs the
client with --server-public-key-path.
Confirm the database leg from the same client session:
upstream_tls block when the backend connection must remain plaintext.
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.