Description:
Concurrent OPTIMIZE and DML on a table of type InnoDB can lead to server instance crash.
The table rebuild via OPTIMIZE runs in online mode.
environment:
* Linux Ubuntu 24.04, x64_64, kernel 6.18
* MySQL standard binary package (mysql-8.4.10-linux-glibc2.28-x86_64.tar.xz, resp. mysql-8.0.45-linux-glibc2.28-x86_64.tar.xz, resp. mysql-5.7.39-linux-glibc2.12-x86_64.tar.gz)
error pattern:
[errorlog v8.4.10]
2026-08-06T11:05:09Z UTC - mysqld got signal 11 ;
Signal SIGSEGV (Invalid permissions for mapped object) at address 0x73f3083d4001
Most likely, you have hit a bug, but this error can also be caused by malfunctioning hardware.
BuildID[sha1]=94a17637d66808cfcd6aa0df1807396f6a073af7
Thread pointer: 0x4e61e000
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
stack_bottom = 73f30860bc30 thread_stack 0x100000
#0 0x18409a0 _Z19handle_fatal_signaliP9siginfo_tPv at mysql-8.4.10/sql/signal_handler.cc:401
#1 0x18409a0 _Z19handle_fatal_signaliP9siginfo_tPv at mysql-8.4.10/sql/signal_handler.cc:391
#2 0x73f41d93132f <unknown>
#3 0xb4ffa0 _Z30rec_init_offsets_comp_ordinaryPKhbPK12dict_index_tPm at mysql-8.4.10/storage/innobase/rem/rec.h:1256
#4 0x1e0356c row_log_table_apply_op at mysql-8.4.10/storage/innobase/row/row0log.cc:2472
#5 0x1336495 row_log_table_apply_ops at mysql-8.4.10/storage/innobase/row/row0log.cc:2995
#6 0x1334cff _Z19row_log_table_applyP9que_thr_tP12dict_table_tP5TABLEP11Alter_stage at mysql-8.4.10/storage/innobase/row/row0log.cc:3084
#7 0x12a9fed _ZZN11ha_innobase24inplace_alter_table_implIN2dd5TableEEEbP5TABLEP18Alter_inplace_infoENKUl7dberr_tE1_clES7_ at mysql-8.4.10/storage/innobase/handler/handler0alter.cc:6260
#8 0x12a9fed _ZN11ha_innobase24inplace_alter_table_implIN2dd5TableEEEbP5TABLEP18Alter_inplace_info at mysql-8.4.10/storage/innobase/handler/handler0alter.cc:6373
#9 0x12a9d6e _ZN11ha_innobase19inplace_alter_tableEP5TABLEP18Alter_inplace_infoPKN2dd5TableEPS5_ at mysql-8.4.10/storage/innobase/handler/handler0alter.cc:1578
#10 0x12a5a26 _ZN7handler22ha_inplace_alter_tableEP5TABLEP18Alter_inplace_infoPKN2dd5TableEPS5_ at mysql-8.4.10/sql/handler.h:6398
#11 0x12a5a26 mysql_inplace_alter_table at mysql-8.4.10/sql/sql_table.cc:13840
#12 0x120f980 _Z17mysql_alter_tableP3THDPKcS2_P14HA_CREATE_INFOP9Table_refP10Alter_info at mysql-8.4.10/sql/sql_table.cc:17716
#13 0x13c8e74 _Z20mysql_recreate_tableP3THDP9Table_refb at mysql-8.4.10/sql/sql_table.cc:18956
#14 0x12365eb _ZL17mysql_admin_tableP3THDP9Table_refP12HA_CHECK_OPTPKc13thr_lock_typebbjPFiS0_S2_S4_EM7handlerFiS0_S4_EiP10Alter_infob.constprop.0 at mysql-8.4.10/sql/sql_admin.cc:1328
#15 0x13c8aaa _ZN22Sql_cmd_optimize_table7executeEP3THD at mysql-8.4.10/sql/sql_admin.cc:1935
#16 0xb876c7 _Z21mysql_execute_commandP3THDb at mysql-8.4.10/sql/sql_parse.cc:4739
#17 0xdaebb3 _Z20dispatch_sql_commandP3THDP12Parser_state at mysql-8.4.10/sql/sql_parse.cc:5406
#18 0xda9b5a _Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command at mysql-8.4.10/sql/sql_parse.cc:2136
#19 0xda63d5 _Z10do_commandP3THD at mysql-8.4.10/sql/sql_parse.cc:1465
#20 0xd81f70 handle_connection at mysql-8.4.10/sql/conn_handler/connection_handler_per_thread.cc:304
#21 0x1043364 pfs_spawn_thread at mysql-8.4.10/storage/perfschema/pfs.cc:3067
#22 0x73f41d988aa3 <unknown>
#23 0x73f41da15c6b <unknown>
#24 0xffffffffffffffff <unknown>
Trying to get some variables.
Some pointers may be invalid and cause the dump to abort.
Query (4e357330): OPTIMIZE TABLE test.testtable
Connection ID (thread ID): 7
Status: NOT_KILLED
The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains
information that should help you find out what is causing the crash.
observation:
* Index appears to be essential. The more columns are member of the index, the more likely the event happens.
* Further non-indexed columns don't seem to have an influence.
* Crash seems independent of innodb_online_alter_log_max_size.
* One single concurrent DML job at a time is sufficient.
* tested in 8.4, 8.0, 5.7
assumption:
Problem during row-log replay.
How to repeat:
principle:
* Create test table with data of sufficient size and one primary key.
* Run OPTIMIZE TABLE in a constant loop.
* Run DML (e.g. INSERT/DELETE or UPDATE) in a constant loop.
* The test data is created in buckets to be touched as a unit. For my tests I have chosen to change existing rows of the table, specifically, simply move the bucket number.
-- test table
CREATE TABLE `test`.`testtable` (
`bucket` INT UNSIGNED NOT NULL DEFAULT '0',
`char_1` VARCHAR(64) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
`char_2` VARCHAR(16) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
`char_3` VARCHAR(16) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
`char_4` VARCHAR(16) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
`char_5` VARCHAR(16) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
`char_6` VARCHAR(16) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
`char_7` VARCHAR(16) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
`char_8` VARCHAR(16) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
PRIMARY KEY (`bucket`, `char_1`, `char_2`, `char_3`, `char_4`, `char_5`, `char_6`, `char_7`, `char_8`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
ROW_FORMAT=DYNAMIC
;
-- fill data
-- use any source table or table combination to provide sufficient number of rows
SET @bucket_size := 20000;
INSERT INTO test.testtable
SELECT ((cnt - 1) DIV @bucket_size) + 1, char_1, char_2, char_3, char_4, char_5, char_6, char_7, char_8
FROM
(
SELECT
ROW_NUMBER() OVER () AS cnt
, UUID() as char_1
, ELT(FLOOR(RAND()*5)+1, 'AAA', 'BBB', 'CCC', 'DDD', 'EEE') as char_2
, ELT(FLOOR(RAND()*5)+1, 'AAA', 'BBB', 'CCC', 'DDD', 'EEE') as char_3
, ELT(FLOOR(RAND()*5)+1, 'AAA', 'BBB', 'CCC', 'DDD', 'EEE') as char_4
, ELT(FLOOR(RAND()*5)+1, 'AAA', 'BBB', 'CCC', 'DDD', 'EEE') as char_5
, ELT(FLOOR(RAND()*5)+1, 'AAA', 'BBB', 'CCC', 'DDD', 'EEE') as char_6
, ELT(FLOOR(RAND()*5)+1, 'AAA', 'BBB', 'CCC', 'DDD', 'EEE') as char_7
, ELT(FLOOR(RAND()*5)+1, 'AAA', 'BBB', 'CCC', 'DDD', 'EEE') as char_8
FROM mysql.time_zone
JOIN mysql.time_zone_transition_type
LIMIT 4000000
) numbered
;
-- run loops
<loop_A>
OPTIMIZE TABLE test.testtable;
<sleep <n>> -- optional
<loop_A_end>
<loop_B>
SELECT MAX(bucket) FROM test.testtable; -- max_bucket
SELECT MIN(bucket) FROM test.testtable; -- min_bucket
INSERT INTO test.testtable SELECT <max_bucket +1>, char_1, char_2, char_3, char_4, char_5, char_6, char_7, char_8 FROM test.testtable WHERE bucket = <min_bucket>;
DELETE FROM test.testtable WHERE bucket = <min_bucket>;
<sleep <n>> -- optional
<loop_B_end>
test notes:
* My testbed let run OPTIMIZE with a break of 2s (optional), the DML with a break of 1s (optional).
* OPTIMIZE took about 4-5s. OPTIMIZE should run sufficiently long to interact with the DML.
* No other jobs were active on the test instance.
* Crash happend mostly within 1 minute. A tighter DML run schedule may increase the crash likelihood.