When MySQL commits a large transaction carrying gigabytes of changes, writing it to the binary log (binlog) can freeze every other commit on the server for minutes. This includes transactions that touch unrelated data. This bottleneck is detrimental to applications that depend on low commit latency. On October 29, 2026, AWS shipped an optimization into community MySQL that removes this bottleneck. We call it Binary Log Optimization for Large Transactions (BOLT). It has been available in Amazon Aurora MySQL since v1.22.0 and in all currently supported major versions (Aurora MySQL 2.x, 3.x, and 8.4.x), where it’s always on for every customer. BOLT is planned to be released as part of a future MySQL innovation release.
BOLT provides three benefits. It makes binlog commit latency for large transactions independent of transaction size, it speeds up binlog crash recovery, and it improves throughput for workloads that mix small and large transactions. Our benchmarks confirm all three results. In this post, we show you the current bottleneck that large transactions hit when committing to the binlog, how BOLT removes that bottleneck on the commit path, and how it also speeds up recovery of large transactions.
Challenges with binlog
When binlog is enabled, each transaction is written to both the binlog and the InnoDB redo log. As the transaction runs its commands, it generates binlog events and buffers them into the binlog cache (IO_CACHE). The size of the binlog cache is controlled by the system variable binlog_cache_size, with a default value of 32 KiB. If a transaction’s events don’t fit in that cache, the server writes the overflow to a temporary file on disk, which is referred to as a “spill file.”
Because each transaction has its own cache or spill file, this work happens fully in parallel across transactions with no serialization or resource contention.
Those parallel writes are then serialized into the binlog through a global lock. The binlog is an append-only file that stores an ordered sequence of transactions, and to preserve that order MySQL serializes commits. At commit, a transaction locks the active binlog file, copies its events from the IO_CACHE or spill file into it, and then unlocks. So even two transactions touching completely different data will commit one at a time.
Figure 1: Standard MySQL binlog commit path, where each transaction serializes through a global lock to copy its events into the active binlog file
The design doesn’t scale for large transactions, because a large transaction holds the lock for the entire duration of its copy and blocks everything else from committing. For example, if a transaction commits 50 GiB of changes and the binlog write runs at about 120 MB/s, the copy takes roughly 7 minutes, and for that entire time no other transaction on the system can commit. It also needs double the disk space while it runs, since the binlog events exist in both the spill file and the main binlog file until the copy finishes. Furthermore, if MySQL restarts while a large transaction’s events are still being copied into the main binlog file, startup is delayed. MySQL has to scan the binlog to confirm the transaction is complete and collect its transaction ID. This design negatively affects availability.
Aurora MySQL solution
AWS contributed an optimization to community MySQL that Aurora MySQL has run in production since November 2019. The optimization removes the copying bottleneck on the commit code path by using the spill file and promoting it into a real binlog file. At transaction commit time, the optimization doesn’t copy binlog events. Instead, it promotes the spill file directly into the binlog sequence by giving it the next binlog file name and adding it to the binlog index. The promotion reuses the steps MySQL already takes when it rotates to a new binlog file. The commit becomes a small, fixed amount of work that doesn’t depend on transaction size. Because the optimization promotes the spill file instead of copying it, the transaction’s events exist in only one place, which also eliminates the double disk space the copy required. Smaller transactions, including those whose events never spill to a file, use the existing commit path. You can see the simplified commit code path in the following figure.
Figure 2: Optimized commit path with BOLT, which promotes the spill file directly into the binlog sequence instead of copying events
You can identify a promoted file through a newly introduced binlog event called Large_transaction_header_event, which appears at the beginning of the promoted binlog file. This event plays an important role in making the promoted file carry the standard binlog file headers, but it is also critical in making recovery of large transactions fast. Binlog recovery typically scans the last active binlog file to check whether the transaction is complete and to collect its XID. With a file promoted through BOLT, it’s guaranteed that if the binlog file has made it to the index, then the transaction is complete. This means we don’t need to scan the transaction (unless source_verify_checksum is set to ON). After the necessary validation, we can immediately seek to the next transaction in the binlog file. Large_transaction_header_event makes this possible because it includes the offset of the transaction’s terminating event, and the recovery logic was modified to seek directly there. Reading a 50 GiB transaction that used to take about 4 minutes now completes in a fraction of a second.
MySQL flags Large_transaction_header_event as ignorable. A consumer that doesn’t recognize it (such as an earlier replica or mysqlbinlog) or a change data capture (CDC) reader (such as Debezium, AWS Database Migration Service (AWS DMS), or Maxwell) skips it and reads the rest of the transaction normally.
Figure 3: Layout of a promoted binlog file led by the Large_transaction_header_event, which earlier consumers skip
You can enable BOLT through a dynamic system variable called binlog_large_transaction_optimization_enabled, which is ON by default. When a transaction’s generated binlog events exceed binlog_large_transaction_optimization_threshold bytes (128 MB by default), the optimization applies to that transaction, and its spilled file is promoted into the main sequence of binlog files, becoming the next active binlog file. To see how many transactions MySQL promoted, query the status variable binlog_large_transaction_optimization_count.
Benchmarking BOLT
The results in this section come from our own controlled benchmarks on the configuration and workloads described here, not from measurements across production customer workloads. Actual results vary with transaction size and mix, instance type, storage, and server configuration.
Test setup. We built BOLT on the latest commit of the MySQL default branch (trunk, as of October 2026), the same implementation proposed upstream. We ran it on an Amazon Elastic Compute Cloud (Amazon EC2) r7i.16xlarge instance (64 vCPUs) with binlog enabled, and data and logs on a 2,048 GiB gp3 volume provisioned at 16,000 IOPS and 1,000 MiB/s. We drove load with sysbench, using its oltp_read_write workload against a dataset of 500 tables of 100,000 rows each. We compared the same build with BOLT on against BOLT off on large-transaction commit latency, binlog crash recovery time, and write throughput. Each data point is the average of three runs. The large transactions we generated each span a single table.
Commit latency. With BOLT off, commit latency grew roughly linearly with transaction size, from about 10 seconds at 1 GiB to about 7 minutes at 50 GiB. With BOLT on, it stayed between about 2 and 2.5 seconds across all sizes we tested. For the 50 GiB transaction in this test, that is about 2.5 seconds with BOLT on versus about 7 minutes with BOLT off. The 2 to 2.5 seconds that remain go to persisting the spill file to durable storage and committing the transaction to InnoDB.
Crash recovery. Forcing recovery of a large transaction on restart, the “BOLT on” configuration kept recovery time at about 0.1 seconds across all sizes we tested. It reads the Large_transaction_header_event and seeks straight to the end of the transaction instead of scanning its body. With the “BOLT off” configuration, recovery time scaled with transaction size, reaching about 4 minutes for the 50 GiB transaction. These figures cover the binlog recovery stage only, not InnoDB rollback or roll-forward.
Write throughput. Over 30-minute runs, throughput improved whenever the workload contained large transactions, because faster commits remove the head-of-line blocking that serializes every other commit behind a large one. In a workload of only 5 GiB transactions, throughput went from 19.3 to 60.8 MB/s of binlog events. In a mixed workload spanning 5 KiB to 5 GiB transactions, it went from 19.9 to 56.1 MB/s.
| Workload | BOLT OFF | BOLT ON | Improvement |
| Large Only (5 GiB) | 19.3 MB/s | 60.8 MB/s | ~3.1x |
| Mixed (5 KiB to 5 GiB) | 19.9 MB/s | 56.1 MB/s | ~2.8x |
On large transactions
While BOLT minimizes the commit and recovery cost for large transactions, our recommendation remains to split your large transactions into smaller batches wherever your application allows. Applying large transactions on binlog replicas remains a challenge, because it reduces replication parallelism. When replica_preserve_commit_order is enabled, no other transaction can commit on the replica until the large transaction commits, which leads to replication lag. By contrast, smaller transactions allow higher parallelism, leading to reduced replication lag and resource pressure.
Collaboration
Upstreaming BOLT has also given us the opportunity to work with engineers, managers, and community members from multiple organizations including Oracle, Alibaba Cloud, and OurSQL Foundation. We would like to thank Tiago Jorge, Karolina Szczepankiewicz, Nuno Carvalho, Libing Song, Henrik Ingo, and Jean-François Gagné for their efforts and guidance throughout this process.
Conclusion
In this post, we discussed BOLT, a new optimization that improves performance for large transactions on binlog in MySQL. The benefits of BOLT are near-constant commit latency and crash recovery time for large transactions, and, as our benchmarks show, higher throughput on workloads that mix large and small transactions. BOLT has been available in Aurora MySQL, enabled by default, since v1.22.0 and in all currently supported major versions (Aurora MySQL 2, 3, and 8.4). It will ship in a future MySQL innovation release, so Aurora MySQL, Amazon Relational Database Service (Amazon RDS) for MySQL, and community MySQL users can all benefit with no changes to their applications. For a deeper look at the design, see the project tracker on GitHub.




