Summary
The ssl_mode connect kwarg does nothing it claims to do: API.MYSQL_OPT_SSL_MODE does not exist in libmariadb. MySQL.jl's mysql_option enum places it at an ordinal that collides with libmariadb's MARIADB_OPT_SKIP_READ_RESPONSE, so:
ssl_mode = SSL_MODE_DISABLED (0) is a silent no-op — TLS stays on;
ssl_mode = SSL_MODE_PREFERRED / REQUIRED / VERIFY_CA / VERIFY_IDENTITY (1–4) actually sets MARIADB_OPT_SKIP_READ_RESPONSE = true, telling the client to stop reading server responses — i.e. asking for more TLS quietly corrupts the connection protocol instead.
This is why the reporter in #234 found ssl_mode = MySQL.API.SSL_MODE_DISABLED "did not resolve the issue", and it also means workloads that believe they've disabled TLS are still running it (relevant to the crash in #220, which is TLS-sensitive).
Details
MySQL.jl's enum (src/api/consts.jl#L219-L224) ends:
MARIADB_OPT_IO_WAIT # 7024
MYSQL_OPT_SSL_MODE # 7025
end
libmariadb's mysql.h (MariaDB_Connector_C_jll 3.4.9, identical prefix through 7024) continues instead:
MARIADB_OPT_IO_WAIT, /* 7024 */
MARIADB_OPT_SKIP_READ_RESPONSE, /* 7025 <- what MySQL.jl's MYSQL_OPT_SSL_MODE hits */
MARIADB_OPT_RESTRICTED_AUTH,
...
There is no MYSQL_OPT_SSL_MODE anywhere in libmariadb — it's a MySQL-Connector/C-only option.
API.setoption sends it as a Ref{Cuint} (src/api/capi.jl#L971-L974, MYSQL_OPT_SSL_MODE ∈ CUINTOPTS), and libmariadb reads one byte of it (mariadb_lib.c v3.4.9, line 3878):
case MARIADB_OPT_SKIP_READ_RESPONSE:
OPT_SET_EXTENDED_VALUE_INT(&mysql->options, skip_read_response, *(my_bool *)arg1);
break;
so on little-endian the enum value 0 → no-op, 1–4 → skip_read_response = true.
Reproduction
Against a stock mysql:8 container (TLS-capable):
using MySQL, DBInterface
conn = DBInterface.connect(MySQL.Connection, "127.0.0.1", "root", "";
db="test", port=3306, ssl_mode=MySQL.API.SSL_MODE_DISABLED)
first(DBInterface.execute(conn, "SHOW STATUS LIKE 'Ssl_cipher'")).Value
# "TLS_AES_256_GCM_SHA384" <- TLS very much not disabled
Related behavior worth documenting while fixing this
With MariaDB_Connector_C_jll 3.4.x there is no way to force a plaintext connection to a TLS-capable server at all: libmariadb 3.4 sets use_ssl by default, and the only escape hatch (plugins/auth/my_auth.c) is the plaintext fallback for servers that don't offer TLS, gated on tls_allow_invalid_server_cert:
if (mysql->options.use_ssl && !(mysql->server_capabilities & CLIENT_SSL))
{
if (!mysql->options.extension->tls_allow_invalid_server_cert || ...)
my_set_error(..., "SSL is required, but the server does not support it");
}
i.e. ssl_verify_server_cert = false (the new default from #235) permits connecting to a no-TLS server, but nothing can turn TLS off when the server supports it. ssl_enforce = false doesn't help either. So true SSL_MODE_DISABLED semantics are simply not implementable on top of Connector/C 3.4.
Suggested fix
Remove the ssl_mode kwarg and the bogus MYSQL_OPT_SSL_MODE enum entry (or make passing it throw an ArgumentError explaining the situation and pointing at ssl_verify_server_cert). Anything is better than the current behavior, where SSL_MODE_DISABLED silently does nothing and SSL_MODE_REQUIRED silently breaks the wire protocol.
Environment: MySQL.jl 1.5.1 (enum unchanged on current main/1.5.2), MariaDB_Connector_C_jll 3.4.9+1, Julia 1.12.6, macOS aarch64, server mysql:8 (8.4.11).
Summary
The
ssl_modeconnect kwarg does nothing it claims to do:API.MYSQL_OPT_SSL_MODEdoes not exist in libmariadb. MySQL.jl'smysql_optionenum places it at an ordinal that collides with libmariadb'sMARIADB_OPT_SKIP_READ_RESPONSE, so:ssl_mode = SSL_MODE_DISABLED(0) is a silent no-op — TLS stays on;ssl_mode = SSL_MODE_PREFERRED / REQUIRED / VERIFY_CA / VERIFY_IDENTITY(1–4) actually setsMARIADB_OPT_SKIP_READ_RESPONSE = true, telling the client to stop reading server responses — i.e. asking for more TLS quietly corrupts the connection protocol instead.This is why the reporter in #234 found
ssl_mode = MySQL.API.SSL_MODE_DISABLED"did not resolve the issue", and it also means workloads that believe they've disabled TLS are still running it (relevant to the crash in #220, which is TLS-sensitive).Details
MySQL.jl's enum (
src/api/consts.jl#L219-L224) ends:libmariadb's
mysql.h(MariaDB_Connector_C_jll 3.4.9, identical prefix through 7024) continues instead:There is no
MYSQL_OPT_SSL_MODEanywhere in libmariadb — it's a MySQL-Connector/C-only option.API.setoptionsends it as aRef{Cuint}(src/api/capi.jl#L971-L974,MYSQL_OPT_SSL_MODE ∈ CUINTOPTS), and libmariadb reads one byte of it (mariadb_lib.cv3.4.9, line 3878):so on little-endian the enum value 0 → no-op, 1–4 →
skip_read_response = true.Reproduction
Against a stock
mysql:8container (TLS-capable):Related behavior worth documenting while fixing this
With MariaDB_Connector_C_jll 3.4.x there is no way to force a plaintext connection to a TLS-capable server at all: libmariadb 3.4 sets
use_sslby default, and the only escape hatch (plugins/auth/my_auth.c) is the plaintext fallback for servers that don't offer TLS, gated ontls_allow_invalid_server_cert:i.e.
ssl_verify_server_cert = false(the new default from #235) permits connecting to a no-TLS server, but nothing can turn TLS off when the server supports it.ssl_enforce = falsedoesn't help either. So trueSSL_MODE_DISABLEDsemantics are simply not implementable on top of Connector/C 3.4.Suggested fix
Remove the
ssl_modekwarg and the bogusMYSQL_OPT_SSL_MODEenum entry (or make passing it throw anArgumentErrorexplaining the situation and pointing atssl_verify_server_cert). Anything is better than the current behavior, whereSSL_MODE_DISABLEDsilently does nothing andSSL_MODE_REQUIREDsilently breaks the wire protocol.Environment: MySQL.jl 1.5.1 (enum unchanged on current
main/1.5.2), MariaDB_Connector_C_jll 3.4.9+1, Julia 1.12.6, macOS aarch64, server mysql:8 (8.4.11).