GA

2026/02/02

DBD::mysqlで mysql_ssl => 1すると接続が SSL connection error: self signed certificate で転ける理由

TL;DR

  • 単に mysql_ssl=1 で接続しようとすると転ける

  • mysql_ssl=1;mysql_ssl_verify_server_cert=0 なら良いかと思うと SSL connection error: Enforcing SSL encryption is not supported without mysql_ssl_verify_server_cert で転ける

  • DBD::mysql が libmysqlclient.so ではなく libmariadb.so とリンクされているとこうなる


$ ldd $(rpm -ql perl-DBD-MySQL | grep mysql.so)

        linux-vdso.so.1 (0x00007fff0e77b000)

        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f23f7a07000)

        libmariadb.so.3 => /lib64/libmariadb.so.3 (0x00007f23f77b2000)      <---- いた

        libperl.so.5.26 => /lib64/libperl.so.5.26 (0x00007f23f73a3000)

        libc.so.6 => /lib64/libc.so.6 (0x00007f23f6fcc000)

        /lib64/ld-linux-x86-64.so.2 (0x00007f23f7e47000)

        libz.so.1 => /lib64/libz.so.1 (0x00007f23f6db4000)

        libdl.so.2 => /lib64/libdl.so.2 (0x00007f23f6bb0000)

        libm.so.6 => /lib64/libm.so.6 (0x00007f23f682e000)

        libssl.so.1.1 => /lib64/libssl.so.1.1 (0x00007f23f6599000)

        libcrypto.so.1.1 => /lib64/libcrypto.so.1.1 (0x00007f23f60ae000)

        libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f23f5e96000)

        libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f23f5c6d000)

        libutil.so.1 => /lib64/libutil.so.1 (0x00007f23f5a69000)

単に mysql --ssl-mode=required と同じことをしたいだけなのに

$ mysql -h 127.0.0.1 -P 64080 -u yoku0825 --ssl-mode=required -sse "SHOW SESSION STATUS LIKE 'Ssl_cipher'"
Ssl_cipher      TLS_AES_128_GCM_SHA256

$ perl -MDBI -MData::Dumper -E 'my $conn= DBI->connect("dbi:mysql:;host=127.0.0.1;port=64080;mysql_ssl=1", "yoku0825")'
DBI connect(';host=127.0.0.1;port=64080;mysql_ssl=1','yoku0825',...) failed: SSL connection error: self signed certificate in certificate chain at -e line 1.

怒られる。
証明書が自己署名なのはそう(単に mysqld --initialize の時の auto_generate_certs=ON の設定で作られるやつだから)だけど、エラーになってほしくはない。でも mysql_ssl=0 にはしたくない(経路の暗号化はしてほしい)

というか、 mysql コマンドラインクライアントは文句を言わないので DBD::mysql の時だけ何かがおかしい。ということは。

$ rpm -ql perl-DBD-MySQL | grep mysql.so
/usr/lib64/perl5/vendor_perl/auto/DBD/mysql/mysql.so

$ ldd /usr/lib64/perl5/vendor_perl/auto/DBD/mysql/mysql.so
        linux-vdso.so.1 (0x00007ffc71bcb000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fe5bb2d7000)
        libmariadb.so.3 => /lib64/libmariadb.so.3 (0x00007fe5bb082000)
        libz.so.1 => /lib64/libz.so.1 (0x00007fe5bae6a000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fe5bac66000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fe5ba8e4000)
        libssl.so.1.1 => /lib64/libssl.so.1.1 (0x00007fe5ba64f000)
        libcrypto.so.1.1 => /lib64/libcrypto.so.1.1 (0x00007fe5ba164000)
        libperl.so.5.26 => /lib64/libperl.so.5.26 (0x00007fe5b9d55000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fe5b997f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe5bb717000)
        libresolv.so.2 => /lib64/libresolv.so.2 (0x00007fe5b9767000)
        libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007fe5b953e000)
        libutil.so.1 => /lib64/libutil.so.1 (0x00007fe5b933a000)

やっぱりlibmariadbにリンクされてる。
libmysqlclientで試してみるために cpanm --look でビルドしてみる。

$ cpanm --look DBD::mysql
$ perl Makefile.PL

PLEASE NOTE:

For 'make test' to run properly, you must ensure that the
database user 'yoku0825' can connect to your MySQL server
and has the proper privileges that these tests require such
as 'drop table', 'create table', 'drop procedure', 'create procedure'
as well as others.

mysql> CREATE USER 'yoku0825'@'localhost' IDENTIFIED BY 's3kr1t';
mysql> GRANT ALL PRIVILEGES ON test.* TO 'yoku0825'@'localhost';

You can also optionally set the user to run 'make test' with:

perl Makefile.PL --testuser=username

I will use the following settings for compiling and testing:

  cflags        (mysql_config) = -I/usr/include/mysql -m64
  ldflags       (mysql_config) =
  libs          (mysql_config) = -L/usr/lib64/mysql -lmysqlclient -lpthread -ldl -lssl -lcrypto -lresolv -lm -lrt
  mysql_config  (guessed     ) = mysql_config
  nocatchstderr (default     ) = 0
  nofoundrows   (default     ) = 0
  testdb        (default     ) = test
  testhost      (default     ) =
  testpassword  (default     ) =
  testport      (default     ) =
  testsocket    (default     ) =
  testuser      (guessed     ) = yoku0825
  version       (mysql_config) = 8.4.8

To change these settings, see 'perl Makefile.PL --help' and
'perldoc DBD::mysql::INSTALL'.

Checking if libs are available for compiling...
Looks good.

Checking if your kit is complete...
Looks good
Warning: prerequisite Test::Deep 0 not found.
Using DBI 1.641 (for perl 5.026003 on x86_64-linux-thread-multi) installed in /usr/lib64/perl5/vendor_perl/auto/DBI/
Generating a Unix-style Makefile
Writing Makefile for DBD::mysql
Writing MYMETA.yml and MYMETA.json

$ make
cp lib/DBD/mysql/INSTALL.pod blib/lib/DBD/mysql/INSTALL.pod
cp lib/DBD/mysql.pm blib/lib/DBD/mysql.pm
cp lib/DBD/mysql/GetInfo.pm blib/lib/DBD/mysql/GetInfo.pm
Running Mkbootstrap for mysql ()
chmod 644 "mysql.bs"
"/usr/bin/perl" -MExtUtils::Command::MM -e 'cp_nonempty' -- mysql.bs blib/arch/auto/DBD/mysql/mysql.bs 644
gcc -c  -I/usr/lib64/perl5/vendor_perl/auto/DBI -I/usr/include/mysql -m64 -g  -D_REENTRANT -D_GNU_SOURCE -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fwrapv -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -g   -DVERSION=\"5.013\" -DXS_VERSION=\"5.013\" -fPIC "-I/usr/lib64/perl5/CORE"   dbdimp.c
"/usr/bin/perl" -p -e "s/~DRIVER~/mysql/g" /usr/lib64/perl5/vendor_perl/auto/DBI/Driver.xst > mysql.xsi
"/usr/bin/perl" "/usr/share/perl5/vendor_perl/ExtUtils/xsubpp"  -typemap '/usr/share/perl5/ExtUtils/typemap'  mysql.xs > mysql.xsc
Warning: duplicate function definition 'do' detected in mysql.xs, line 142
Warning: duplicate function definition 'rows' detected in mysql.xs, line 550
mv mysql.xsc mysql.c
gcc -c  -I/usr/lib64/perl5/vendor_perl/auto/DBI -I/usr/include/mysql -m64 -g  -D_REENTRANT -D_GNU_SOURCE -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fwrapv -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -g   -DVERSION=\"5.013\" -DXS_VERSION=\"5.013\" -fPIC "-I/usr/lib64/perl5/CORE"   mysql.c
gcc -c  -I/usr/lib64/perl5/vendor_perl/auto/DBI -I/usr/include/mysql -m64 -g  -D_REENTRANT -D_GNU_SOURCE -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fwrapv -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -g   -DVERSION=\"5.013\" -DXS_VERSION=\"5.013\" -fPIC "-I/usr/lib64/perl5/CORE"   socket.c
rm -f blib/arch/auto/DBD/mysql/mysql.so
gcc  -lpthread -shared -Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -L/usr/local/lib -fstack-protector-strong  dbdimp.o mysql.o socket.o  -o blib/arch/auto/DBD/mysql/mysql.so  \
   -L/usr/lib64/mysql -lmysqlclient -lpthread -ldl -lssl -lcrypto -lresolv -lm -lrt -lperl   \

chmod 755 blib/arch/auto/DBD/mysql/mysql.so
Manifying 2 pod documents

$ exit

$ find -name mysql.so
./.cpanm/work/1769741347.2091827/DBD-mysql-5.013/blib/arch/auto/DBD/mysql/mysql.so

LD_PRELOAD.cpanm にできた mysql.so の方を使う形にして試してみる。

$ LD_PRELOAD=./.cpanm/work/1769741347.2091827/DBD-mysql-5.013/blib/arch/auto/DBD/mysql/mysql.so perl -MDBI -MData::Dumper -E 'my $conn= DBI->connect("dbi:mysql:;host=127.0.0.1;port=64080;mysql_ssl=1", "yoku0825")'

できた…
DBD::MySQLのバージョンのせいだと嫌なので念のため mariadb-connector-c-devel を入れ直して試してみる。

$ perl Makefile.PL

PLEASE NOTE:

For 'make test' to run properly, you must ensure that the
database user 'yoku0825' can connect to your MySQL server
and has the proper privileges that these tests require such
as 'drop table', 'create table', 'drop procedure', 'create procedure'
as well as others.

mysql> CREATE USER 'yoku0825'@'localhost' IDENTIFIED BY 's3kr1t';
mysql> GRANT ALL PRIVILEGES ON test.* TO 'yoku0825'@'localhost';

You can also optionally set the user to run 'make test' with:

perl Makefile.PL --testuser=username

I will use the following settings for compiling and testing:

  cflags        (mysql_config) = -I/usr/include/mysql -I/usr/include/mysql/mysql
  ldflags       (mysql_config) =
  libs          (mysql_config) = -L/usr/lib64/ -lmariadb
  mysql_config  (guessed     ) = mysql_config
  nocatchstderr (default     ) = 0
  nofoundrows   (default     ) = 0
  testdb        (default     ) = test
  testhost      (default     ) =
  testpassword  (default     ) =
  testport      (default     ) =
  testsocket    (default     ) =
  testuser      (guessed     ) = yoku0825
  version       (mysql_config) = 10.5.5

To change these settings, see 'perl Makefile.PL --help' and
'perldoc DBD::mysql::INSTALL'.

Checking if libs are available for compiling...

The chosen MySQL client library appears to be MariaDB's. Compilation may fail.
Consider DBD::MariaDB or installing Oracle's MySQL client library.

Checking if your kit is complete...
Looks good
Using DBI 1.641 (for perl 5.026003 on x86_64-linux-thread-multi) installed in /usr/lib64/perl5/vendor_perl/auto/DBI/
Generating a Unix-style Makefile
Writing Makefile for DBD::mysql
Writing MYMETA.yml and MYMETA.json

$ make
cp lib/DBD/mysql/INSTALL.pod blib/lib/DBD/mysql/INSTALL.pod
cp lib/DBD/mysql.pm blib/lib/DBD/mysql.pm
cp lib/DBD/mysql/GetInfo.pm blib/lib/DBD/mysql/GetInfo.pm
Running Mkbootstrap for mysql ()
chmod 644 "mysql.bs"
"/usr/bin/perl" -MExtUtils::Command::MM -e 'cp_nonempty' -- mysql.bs blib/arch/auto/DBD/mysql/mysql.bs 644
gcc -c  -I/usr/lib64/perl5/vendor_perl/auto/DBI -I/usr/include/mysql -I/usr/include/mysql/mysql -g  -D_REENTRANT -D_GNU_SOURCE -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fwrapv -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -g   -DVERSION=\"5.013\" -DXS_VERSION=\"5.013\" -fPIC "-I/usr/lib64/perl5/CORE"   dbdimp.c
dbdimp.c: In function 'parse_params':
dbdimp.c:639:22: warning: implicit declaration of function 'mysql_real_escape_string_quote'; did you mean 'mysql_real_escape_string'? [-Wimplicit-function-declaration]
               ptr += mysql_real_escape_string_quote(sock, ptr, valbuf, vallen, '\'');
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                      mysql_real_escape_string
dbdimp.c: In function 'mysql_dr_connect':
dbdimp.c:1244:31: error: 'MYSQL_OPT_COMPRESSION_ALGORITHMS' undeclared (first use in this function); did you mean 'MYSQL_OPT_COMPRESS'?
           mysql_options(sock, MYSQL_OPT_COMPRESSION_ALGORITHMS, calg);
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                               MYSQL_OPT_COMPRESS
dbdimp.c:1244:31: note: each undeclared identifier is reported only once for each function it appears in
dbdimp.c:1415:31: error: 'MYSQL_OPT_GET_SERVER_PUBLIC_KEY' undeclared (first use in this function); did you mean 'MYSQL_SERVER_PUBLIC_KEY'?
           mysql_options(sock, MYSQL_OPT_GET_SERVER_PUBLIC_KEY, &server_get_pubkey);
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                               MYSQL_SERVER_PUBLIC_KEY
dbdimp.c:1479:22: error: 'SSL_MODE_PREFERRED' undeclared (first use in this function); did you mean 'SO_PEERCRED'?
           ssl_mode = SSL_MODE_PREFERRED;
                      ^~~~~~~~~~~~~~~~~~
                      SO_PEERCRED
dbdimp.c:1481:19: error: 'SSL_MODE_VERIFY_IDENTITY' undeclared (first use in this function)
        ssl_mode = SSL_MODE_VERIFY_IDENTITY;
                   ^~~~~~~~~~~~~~~~~~~~~~~~
dbdimp.c:1483:19: error: 'SSL_MODE_VERIFY_CA' undeclared (first use in this function)
        ssl_mode = SSL_MODE_VERIFY_CA;
                   ^~~~~~~~~~~~~~~~~~
dbdimp.c:1485:19: error: 'SSL_MODE_REQUIRED' undeclared (first use in this function); did you mean 'OP_REQUIRE'?
        ssl_mode = SSL_MODE_REQUIRED;
                   ^~~~~~~~~~~~~~~~~
                   OP_REQUIRE
dbdimp.c:1486:30: error: 'MYSQL_OPT_SSL_MODE' undeclared (first use in this function); did you mean 'MYSQL_OPT_SSL_CRL'?
      if (mysql_options(sock, MYSQL_OPT_SSL_MODE, &ssl_mode) != 0) {
                              ^~~~~~~~~~~~~~~~~~
                              MYSQL_OPT_SSL_CRL
dbdimp.c:1495:30: error: 'SSL_MODE_DISABLED' undeclared (first use in this function); did you mean 'SS_DISABLE'?
      unsigned int ssl_mode = SSL_MODE_DISABLED;
                              ^~~~~~~~~~~~~~~~~
                              SS_DISABLE
dbdimp.c: In function 'mysql_st_prepare':
dbdimp.c:2419:24: warning: assignment to 'my_bool *' {aka 'char *'} from incompatible pointer type '_Bool *' [-Wincompatible-pointer-types]
           bind->is_null=      &(fbind->is_null);
                        ^
dbdimp.c: In function 'mysql_st_internal_execute41':
dbdimp.c:2856:9: warning: implicit declaration of function 'mysql_stmt_bind_named_param'; did you mean 'mysql_stmt_bind_param'? [-Wimplicit-function-declaration]
     if (mysql_stmt_bind_named_param(stmt,bind,num_params, NULL))
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
         mysql_stmt_bind_param
dbdimp.c:2915:63: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'my_ulonglong' {aka 'long long unsigned int'} [-Wformat=]
                   "\t<- mysql_internal_execute_41 returning %lu rows\n",
                                                             ~~^
                                                             %llu
                   rows);
                   ~~~~
dbdimp.c: In function 'mysql_st_execute':
dbdimp.c:3076:32: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'my_ulonglong' {aka 'long long unsigned int'} [-Wformat=]
     sprintf(actual_row_num, "%lu", imp_sth->row_num);
                              ~~^   ~~~~~~~~~~~~~~~~
                              %llu
dbdimp.c: In function 'mysql_describe':
dbdimp.c:3170:22: warning: assignment to 'my_bool *' {aka 'char *'} from incompatible pointer type '_Bool *' [-Wincompatible-pointer-types]
       buffer->is_null= &(fbh->is_null);
                      ^
dbdimp.c:3171:20: warning: assignment to 'my_bool *' {aka 'char *'} from incompatible pointer type '_Bool *' [-Wincompatible-pointer-types]
       buffer->error= (bool*) &(fbh->error);
                    ^
dbdimp.c: In function 'mysql_st_fetch':
dbdimp.c:3475:63: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'my_ulonglong' {aka 'long long unsigned int'} [-Wformat=]
       PerlIO_printf(DBIc_LOGPIO(imp_xxh), "\tmysql_num_rows=%lu\n",
                                                             ~~^
                                                             %llu
                     mysql_num_rows(imp_sth->result));
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dbdimp.c:3477:68: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'my_ulonglong' {aka 'long long unsigned int'} [-Wformat=]
       PerlIO_printf(DBIc_LOGPIO(imp_xxh), "\tmysql_affected_rows=%lu\n",
                                                                  ~~^
                                                                  %llu
                     mysql_affected_rows(imp_dbh->pmysql));
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dbdimp.c: In function 'mysql_st_FETCH_attrib':
dbdimp.c:4081:60: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'my_ulonglong' {aka 'long long unsigned int'} [-Wformat=]
           PerlIO_printf(DBIc_LOGPIO(imp_xxh), "INSERT ID %lu\n", imp_sth->insertid);
                                                          ~~^     ~~~~~~~~~~~~~~~~~
                                                          %llu
make: *** [Makefile:352: dbdimp.o] Error 1

あっ make転けた…
じゃあDBD::MariaDB(ちゃんと存在するのだ)で試す。

$ sudo cpanm DBD::MariaDB
..

$ perl -MDBI -MData::Dumper -E 'my $conn= DBI->connect("dbi:MariaDB:;host=127.0.0.1;port=64080;mysql_ssl=1", "yoku0825")'
DBI connect(';host=127.0.0.1;port=64080;mysql_ssl=1','yoku0825',...) failed: Unknown attribute mysql_ssl at -e line 1.

今度は mysql_ssl なんて知らんと言われた… mariadb_ssl らしいんだけど、別にここはコンパチってわけではないのか。

$ perl -MDBI -MData::Dumper -E 'my $conn= DBI->connect("dbi:MariaDB:;host=127.0.0.1;port=64080;mariadb_ssl=1", "yoku0825")'
DBI connect(';host=127.0.0.1;port=64080;mariadb_ssl=1','yoku0825',...) failed: SSL connection error: self signed certificate in certificate chain at -e line 1.

うむ、やはりlibmariadbに依存しそう。

ただ、これがどこのコードから派生しているのかよくわからん…。

大体にして、そもそも mariadb コマンドラインクライアントは

$ ./client/mariadb -h 127.0.0.1 -P 64080 -u yoku0825 --ssl -sse "SHOW SESSION STATUS LIKE 'Ssl_cipher'"
Ssl_cipher      TLS_AES_256_GCM_SHA384

ちゃんとつながるんである!
mariadb コマンドラインクライアントが SSL connection error: self signed certificate で転けるのは --ssl-verify-server-cert をつけた時だけ。

$ ./client/mariadb -h 127.0.0.1 -P 64080 -u yoku0825 --ssl --ssl-verify-server-cert -sse "SHOW SESSION STATUS LIKE 'Ssl_cipher'"
ERROR 2026 (HY000): TLS/SSL error: self signed certificate in certificate chain

じゃあDBD::mysqlも mysql_ssl_verify_server_cert=0 してやればいいかと思うと

$ perl -MDBI -MData::Dumper -E 'my $conn= DBI->connect("dbi:mysql:;host=127.0.0.1;port=64080;mysql_ssl=1;mysql_ssl_verify_server_cert=0", "yoku0825")'
DBI connect(';host=127.0.0.1;port=64080;mysql_ssl=1;mysql_ssl_verify_server_cert=0','yoku0825',...) failed: SSL connection error: Enforcing SSL encryption is not supported without mysql_ssl_verify_server_cert at -e line 1.

今度は Enforcing SSL encryption is not supported without mysql_ssl_verify_server_cert で転けるのである…。

libmysqlclientにリンクしたDBD::mysqlならこっちも文句は言わない。

$ LD_PRELOAD=~/.cpanm/work/1769741347.2091827/DBD-mysql-5.013/blib/arch/auto/DBD/mysql/mysql.so perl -MDBI -MData::Dumper -E 'my $conn= DBI->connect("dbi:mysql:;host=127.0.0.1;port=64080;mysql_ssl=1;mysql_ssl_verify_server_cert=0", "yoku0825")'

わからない…。

2025/12/25

MySQL 8.0のEOLに際して、ぼくと8.0のおもいで

この記事は MySQL - Qiita Advent Calendar 2025 の25日目の記事です。メリークリスマス!

昨日は日本で一番MySQL Studioに詳しいという噂の mikoma さんによる MySQL AIとMySQL Studioをざっくりと でした。


さて掲題のとおりMySQL 8.0が来年 2026年の4月にEOL (End Of Lifetime) を迎えるわけですが、MySQL 8.0の思い出でもちょっと。

一言で言うと「あれだけ我々を ~苦しめて~ 盛り上げてきた8.0が終わるという感じ」

MySQL 8.0の話はずっとしていたような気がします。が、思えばGAが2018年で、俺がMySQLを本格的に始めたのは2012年なので、MySQL人生の半分はMySQL 8.0でした。そりゃずっと話してる気もするわって感じなのです。



まだ8.0がGAになる前…楽しそうですね俺。
5.7は ~MySQL Fabricとともに~ 結構新機能を使い倒した感があったので、更に機能が増える(であろう) 8.0にとても期待していたのがわかります。



実際に8.0がロールアウトされて、本番導入をほぼほぼ意識していた(というかこの時はもう現用環境とレプリケーションを組んでいたはず)頃。まだ ~悪夢ではない~ 夢を見ていそうです。



ほぼ同時期のスライド。「パッチバージョンで非互換wwww」とか言っていたものの、自分の本番環境ではまだカットオーバーされていないからか笑い話にしているフシがありますね。


致命的なバグを含まない最新版MySQLを探すには? 『MySQL徹底入門』共著者が語る、バージョン選びのポイント | ログミーBusiness


このへんでコロナ禍を挟んで活動が減ってたり転職したりしてますが、2022年には8.0を楽しむどころかこうなっていた模様。



その間にMySQL 4.0(バージョン50%削減)と付き合ったりもしていました。



8.4のリリースで「安心して使える8.0だと思えば」と言っているあたり、8.0時代が本当につらかったんだなあと思い起こさせます。



今はなんと8.xを飛び越えて10.xの世界線にいますが、またいずれ9.7の世界線で会えることを楽しみにしています。

さあ、それはさておきMySQL 8.0のEOLは来年 2026年の4月ですからね! あと1営業日しかありませんが今から8.4に行く準備をしておきましょう。良いお年を!

2025/12/21

MySQL RouterのRead-Write Splitting…の前に、前提条件になっているConnection Sharingについて見てみたらMySQL Proxyのことを思い出した

この記事は MySQL - Qiita Advent Calendar 2025 の21日目の記事です。

昨日は @meijik さんの MedianやPercentile_%が欲しい連合会(Firebird/MySQL) でした。


ふと MySQL RouterのRead-Write Splittingの設定 を見ていたら、前提条件として connection_sharing: must be set to 1. と書いてあって、俺が使っていた8.0の頃のRouterと比べて増えたなあと思って調べてみた。

MySQL :: MySQL Router 8.4 :: 3.4 Connection Sharing and Reuse

MySQL Router enables server connections to be pooled and shared

ってことなので、MySQLとMySQL Routerの間のコネクションを、MySQL Routerとアプリケーションの間で使い回させられるような感じになるはず。

折角なので(?) 最新のMySQL Router(Innovation Release)にしてみる(8.4でもできたんだけどなんか勘違いして最新版を入れてしまったのでそれでやる)

$ sudo dnf install mysql-router --disablerepo="*" --enablerepo="mysql-tools-innovation*"
..
=======================================================================================================================================
 Package                             Architecture        Version                   Repository                                     Size
=======================================================================================================================================
Upgrading:
 mysql-router-community              x86_64              9.5.0-1.el8               mysql-tools-innovation-community               61 M
..

mysqlrouter.conf を昔取った杵柄でテキトーにいじってみる。

$ sudo vim /etc/mysqlrouter/mysqlrouter.conf
..
[connection_pool]
idle_timeout= 3600
max_idle_server_connections= 10

[routing:test_connection_sharing]
bind_address= 127.0.0.1
bind_port= 49825
destinations= 127.0.0.1:64080
routing_strategy= first-available
connection_sharing= 1
client_ssl_mode = disabled

$ sudo systemctl start mysqlrouter

$ sudo less /var/log/mysqlrouter/mysqlrouter.log
2025-12-21 13:25:24 main SYSTEM [7f938e74b580] Starting 'MySQL Router', version: 9.5.0 (MySQL Community - GPL)
2025-12-21 13:25:24 io INFO [7f938e74b580] starting 8 io-threads, using backend 'linux_epoll'
2025-12-21 13:25:24 keepalive INFO [7f93817fa700] keepalive started with interval 60
2025-12-21 13:25:24 keepalive INFO [7f93817fa700] keepalive
2025-12-21 13:25:24 routing INFO [7f9380ff9700] [routing:test_connection_sharing] started: routing strategy = first-available
2025-12-21 13:25:24 routing INFO [7f9380ff9700] Start accepting connections for routing routing:test_connection_sharing listening on '127.0.0.1:49825'

max_idle_server_connectionsidle_timeout[connection_pool] セクションなので [routing:*] セクションに書いても読んでくれない。

ともあれこれで

$ mysql -h127.0.0.1 -P49825 -uyoku0825 -sse "SELECT CONNECTION_ID()"
35467

$ mysql -h127.0.0.1 -P49825 -uyoku0825 -sse "SELECT CONNECTION_ID()"
35467

$ mysql -h127.0.0.1 -P49825 -uyoku0825 -sse "SELECT CONNECTION_ID()"
35467> 

$ mysql -h127.0.0.1 -P49825 -uyoku0825 -sse "SELECT CONNECTION_ID()"
35467

うん、クライアントを切断しても CONNECTION_ID() の結果が変わらないのでプーリング(シェアリング)できてるっぽい。

で、ここからが本題。

3.4 Connection Sharing and Reuse を読むと、

Unsupported SQL Features
The following statements and functions are not supported when connection sharing is active, except inside a transaction.
..

  • LAST_INSERT_ID()

と、コネクションシェアリングでは使えないらしい関数が示されている。

$ mysql -h127.0.0.1 -P49825 -uyoku0825

mysql> SELECT LAST_INSERT_ID();
ERROR 3566 (HY000): Access to native function is rejected when connection sharing is enabled

確かにエラーになる。

$ ./runtime_output_directory/perror 3566
MySQL error code MY-003566 (ER_NO_ACCESS_TO_NATIVE_FCT): Access to native function '%.64s' is rejected.

MySQLサーバー側のperrorでもちゃんと返ってきたけれど、なんかよく見るとエラーメッセージがしっくり来ていない ( %.64sis rejectedshwn connection sharing is enabled が綺麗に対応していない )

あと、 performance_schema.events_errors_summary_global_by_error に記録されてないのでこれはMySQLサーバから来てるんじゃなくてMySQL Routerがエラーパケット作ってるっぽい。

mysql80 35513> SELECT * FROM events_errors_summary_global_by_error WHERE error_number = 3566;
+--------------+----------------------------+-----------+------------------+-------------------+------------+-----------+
| ERROR_NUMBER | ERROR_NAME                 | SQL_STATE | SUM_ERROR_RAISED | SUM_ERROR_HANDLED | FIRST_SEEN | LAST_SEEN |
+--------------+----------------------------+-----------+------------------+-------------------+------------+-----------+
|         3566 | ER_NO_ACCESS_TO_NATIVE_FCT | HY000     |                0 |                 0 | NULL       | NULL      |
+--------------+----------------------------+-----------+------------------+-------------------+------------+-----------+
1 row in set (0.00 sec)

さて。

こんなこと ( = MySQL Routerが中を通るSQLに応じて勝手にエラーパケットを返す ) ができるということは、つまりMySQL Routerは 流れてくるSQLをパースしているわけで 、そうすると Limitations に書かれている Connection sharing is not supported in PASSTHROUGH mode or if server-ssl-mode=AS_CLIENT and client-ssl-mode=PREFERRED. も、mysqlrouterが終端しない形でSSL/TLSを使ってしまうと流れてくるSQLが読めなくなるからなわけであって、てことはコネクションシェアリングを前提にしているRead-Write SplittingというのはMySQL RouterがSQLをパースしてソースに投げるかレプリカに投げるのかを打ち分けているということで…。

MySQL Proxyの rw-splitting.lua とか思い出して見てみたら、弾いてる関数とかが似ていて、繰り返す歴史を感じたという感じでした。

明日は @tmtms さんです!