#746·MySQL

Invalid table-level KEY_BLOCK_SIZE leaves stale per-index DD metadata after InnoDB fallback

Author: Ty-IanCreated Sep 8, 2026Updated Sep 8, 2026
Labelsbugneeds-triage

MySQL version / commit

MySQL Community Server trunk

Steps to reproduce

Prerequisites:

  • innodb_page_size=16384
  • innodb_file_per_table=ON
  • InnoDB ROW_FORMAT=COMPRESSED is supported

When innodb_strict_mode is OFF, create a compressed table using the invalid table-level KEY_BLOCK_SIZE=32:

sql
SELECT VERSION(),
       @@GLOBAL.innodb_page_size,
       @@GLOBAL.innodb_file_per_table;

DROP TABLE IF EXISTS k;
SET SESSION innodb_strict_mode=OFF;

CREATE TABLE k (
  id INT PRIMARY KEY,
  c1 INT,
  KEY idx_c1 (c1)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=32;

SHOW WARNINGS;
SHOW CREATE TABLE k;

SELECT NAME, ROW_FORMAT, ZIP_PAGE_SIZE
FROM information_schema.INNODB_TABLES
WHERE NAME=CONCAT(DATABASE(), '/k');

-- The stale per-index values survive a table rebuild.
ALTER TABLE k FORCE;
SHOW CREATE TABLE k;

-- Rebuilding the primary key also retains the stale value.
ALTER TABLE k DROP PRIMARY KEY, ADD PRIMARY KEY (id);
SHOW CREATE TABLE k;

-- Rebuilding the secondary index clears its stale value.
ALTER TABLE k DROP INDEX idx_c1;
ALTER TABLE k ADD INDEX idx_c1 (c1);
SHOW CREATE TABLE k;

DROP TABLE k;

### Expected vs actual result

Expected result
===============

After InnoDB rejects the invalid table-level KEY_BLOCK_SIZE=32 and selects the
final compressed page size, inherited per-index metadata should not retain the
invalid value.

For this case, the inherited index block_size values should either be
normalized to 8 or omitted as inherited metadata. PRIMARY and secondary index
rebuilds should produce consistent metadata.

Actual result
=============

CREATE TABLE emits the expected warning:

Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=32.

InnoDB correctly selects an 8KB compressed page size:

ROW_FORMAT  ZIP_PAGE_SIZE
Compressed  8192

The table-level DD value is also corrected to KEY_BLOCK_SIZE=8. However,
SHOW CREATE TABLE reports stale index-level values:

CREATE TABLE `k` (
  `id` int NOT NULL,
  `c1` int DEFAULT NULL,
  PRIMARY KEY (`id`) KEY_BLOCK_SIZE=32,
  KEY `idx_c1` (`c1`) KEY_BLOCK_SIZE=32
) ENGINE=InnoDB ... ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8

The index-level KEY_BLOCK_SIZE=32 clauses survive ALTER TABLE FORCE and
DROP/ADD PRIMARY KEY.

Dropping and re-adding idx_c1 clears the value for that secondary index, while
PRIMARY still retains KEY_BLOCK_SIZE=32. Primary and secondary index rebuilds
therefore behave inconsistently.

A debug build confirms that mysql.indexes.options contains:

name     options
idx_c1   block_size=32;flags=0;
PRIMARY  block_size=32;flags=0;

The physical compressed page size is correct, and no data corruption has been
observed. This appears to be a data-dictionary metadata consistency issue.

Suspected cause
===============

The server copies a table-level KEY_BLOCK_SIZE into KEY::block_size for each
index, and persists nonzero values as the index DD "block_size" option.

In InnoDB dd_set_table_options(), the final table-level key_block_size is
derived from the finalized InnoDB flags, but the compressed-table path does
not normalize the already-created per-index block_size options. Consequently,
the ignored user value remains in the index DD metadata.

### Platform / compiler

Linux x86_64 GCC/G++ 12.3.0 CMake 3.26.5 Debug build