It’s been a few weeks since our first pre-release for Debezium 3.5, and we’re pleased to announce that the next installment is now available: 3.5.0.Beta1. With an extended cadence since the first alpha, this release is packed with dozens of new features, improvements, and bug fixes. Let’s dive into what’s new!
New features and improvements
Debezium Core
New parallel, multithreaded chunked-based snapshots
A few years ago, Debezium introduced its first iteration of parallel snapshotting. We’re happy to report that the next evolution of this feature is here. The new parallel snapshotting implementation takes the existing solution a step further, allowing you to snapshot a single table across multiple threads using chunking (debezium/dbz#1220).
This feature provides several key guarantees:
-
All snapshot threads are fully utilized for the entire duration of the snapshot, maximizing resource utilization.
-
All tables, regardless of row count, can take advantage of parallel snapshotting.
The feature is controlled by the following configuration options:
snapshot.max.threads-
The number of threads used to parallelize the snapshot. Defaults to
1. snapshot.max.threads.multiplier-
A global multiplier that determines how many chunks to create for each table. When set to
1(the default), Debezium computes (row count / snapshot max threads) to determine the number of chunks. For example, a table with 1M rows and 4 snapshot threads produces 4 chunks of 250,000 rows each.
In scenarios where you cannot increase the number of snapshot threads but need more granular chunking, increase this multiplier. Using the same 1M-row table with 4 threads and a multiplier of 2, Debezium creates 8 chunks of 125,000 rows each. snapshot.max.threads.multiplier.<fully_qualified_table_name>-
A table-specific multiplier that overrides the global multiplier. This allows individual tables to be scaled differently, using more or fewer chunks to accommodate varying table sizes or resource constraints.
| While both the thread count and multiplier can be tuned, increasing the number of threads is generally the most effective way to improve throughput. |
You can also use chunk-based snapshotting without parallelism. Simply configure one or both snapshot.max.threads.multiplier variants to control the chunk count while keeping a single thread.
For existing users who have not set snapshot.max.threads or snapshot.max.threads.multiplier, connectors will continue to operate exactly as before, using the sequential single-threaded snapshot mechanism. No configuration changes are needed.
For users who previously set snapshot.max.threads and prefer the older table-per-thread behavior, set internal.legacy.snapshot.max.threads to true. The legacy parallel snapshot feature will remain available for some time but will eventually be removed in favor of the chunk-based approach.
| The chunk-based parallel snapshot feature has the following limitations:
In these cases, the algorithm assigns a single chunk to these tables, effectively falling back to the table-per-thread strategy. |
Debezium for MySQL
Modify binlog offset position using signals
One of the community’s most requested features is the ability to adjust a connector’s offset position without directly manipulating the offset topic. Debezium 3.5 introduces this capability, starting with MySQL, by allowing users to send a signal that changes the offset position (debezium/dbz#1156).
To use this feature, insert a signal into the signal table as shown below. The <data> payload varies depending on whether the MySQL source database uses GTIDs.
INSERT INTO signal_table values ('test_id', 'set-binlog-position', '<data>'); { "gtid_set": "3E11FA47-71CA-11E1-9E33-C80AA9429562:1-100" } { "binlog_filename": "mysql-bin.000003", "binlog_position": 1234 } Based on community feedback, we plan to roll this feature out to additional connectors in future releases.
Debezium for Oracle
Oracle memory improvements
The Debezium Oracle connector buffers transaction events due to how its CDC integration with Oracle works. This buffer stores column values for each event along with various bookkeeping metadata used for populating the event’s source information block and managing the buffer lifecycle.
While the buffer’s footprint is primarily driven by event column values, we’ve identified several ways to reduce the bookkeeping overhead — either unconditionally or optionally via configuration (debezium/dbz#1425).
No configuration changes are required for existing users. You should see approximately a 50% reduction in the buffer’s bookkeeping footprint, which translates to a lower overall memory footprint for your connector deployment. The improvement is especially noticeable in environments with large transactions.
| An additional 8% bookkeeping reduction can be achieved by setting |
For a deeper look at the impact of these changes, see the pull request description.
New LogMiner advancement strategy
Some Oracle environments inevitably have long-running or large transactions that cannot be avoided. Due to LogMiner’s requirements, Debezium interacts with it in a way that guarantees transaction and data consistency — but this can delay low watermark advancement.
The community has requested more control over when Debezium advances the low watermark, even while long-running or large transactions are in flight. Debezium 3.5 introduces a time-based threshold for controlling low watermark advancement (debezium/dbz#1553).
This feature works similarly to transaction retention: rather than discarding the transaction, it is retained, but the low watermark is advanced. Enable it by setting log.mining.window.max.ms to any value greater than zero.
| LogMiner has specific requirements to guarantee data consistency. Advancing the SCN with this feature introduces risks because those requirements are no longer fully honored. This can lead to transactions that fail to commit, events that appear as unsupported operations, or other LogMiner anomalies. Using this feature acknowledges the above risks. Please carefully evaluate the trade-offs before enabling it in any production pipeline. |
Incremental snapshot performance improvements
Debezium’s incremental snapshot process relies heavily on primary key indexes for efficient row lookup between a chunk’s lower and upper boundaries. As table sizes grow, this efficiency becomes increasingly critical.
A common source of performance degradation with incremental snapshots involves composite keys on very large tables. The SQL predicates required to locate rows between boundaries with composite keys are complex, and not every database engine can optimize them to efficiently use the primary key index.
For Oracle, one way to improve performance is to use ROWID — a unique byte offset for each row — instead of the primary key index. This bypasses the index entirely and operates at the lowest level of the database to isolate the target chunk of rows during incremental snapshots (debezium/dbz#1108).
Debezium for SQL Server
Managed identity support
The SQL Server connector now supports identity-based authentication via the driver.authentication configuration property (debezium/dbz#1153). Set this property to ActiveDirectoryManagedIdentity or the legacy ActiveDirectoryMSI to connect to Azure SQL databases.
Improved transaction metadata handling
Debezium has historically lacked a reliable way to identify when SQL Server transactions end. As a result, the transaction END marker was emitted only after the first event of the next transaction, leading to delayed delivery in low-traffic systems when using provide.transaction.metadata.
Debezium 3.5 addresses this by leveraging dm_cdc_log_scan_sessions to detect when transactions have completed (debezium/dbz#1604). This allows END markers to be emitted more promptly, particularly in low-traffic environments.
| This improvement only applies to connectors deployed with |
Debezium JDBC sink
PostgreSQL unnest support
PostgreSQL’s UNNEST function expands an array into a set of rows, and the Debezium JDBC sink connector can now leverage it. Enable this for insert and upsert modes by setting dialect.postgres.unnest.insert.enabled to true (debezium/dbz#1525).
The unnest function allows the JDBC sink connector to write multiple rows in a single JDBC SQL operation, reducing overhead and significantly increasing write throughput.
There are several limitations to be aware of:
-
Update and delete operations continue to use the standard JDBC batch mechanism.
-
PostgreSQL imposes an upper limit of 65,535 parameters per statement. For tables with many columns, be mindful of the batch size to avoid exceeding this limit.
-
Batches containing a single row fall back to the standard
INSERT INTO … ON CONFLICTsyntax, as unnest provides no benefit for single-row operations. -
Because unnest requires all rows in a batch to share the same schema, any change in a table’s column count forces an early flush of the buffer.
For most environments, these limitations won’t be encountered, but they’re worth keeping in mind.
IBMi support
As Debezium’s source connector portfolio continues to grow, our goal is to provide comprehensive parity with the JDBC sink to enable full homogeneous replication between the same source and target databases. With that in mind, the Debezium JDBC sink connector now supports IBMi target databases (debezium/dbz#1497).
Debezium Server
NATS JetStream configurable naming
The Debezium Server NATS JetStream stream name can now be configured through the debezium.sink.nats-jetstream.stream-name deployment property. This property is optional and remains backward compatible — existing deployments continue to use the default DebeziumStream (debezium/dbz#1581).
This change enables multiple Debezium Server instances to share the same NATS JetStream.
Debezium Platform
First-time guided tour
When exploring new software for the first time, a guided tour can be a great way to quickly become familiar with what the solution offers.
Debezium 3.5 continues to invest in the user experience with a new guided walkthrough feature in the Platform UI (debezium/dbz#1244). The tour offers two modes: a quick guide for a rapid overview, or an advanced tour that walks you through creating a new pipeline step by step.
Debezium Quarkus Extensions
Support for Oracle
The Debezium Quarkus extensions now include support for the Oracle connector (debezium/dbz#1389). In a Quarkus application backed by Oracle, developers can respond to real-time changes by including the new Oracle module:
<dependency> <groupId>io.debezium.quarkus</groupId> <artifactId>debezium-quarkus-oracle</artifactId> <version>v3.5.0.Beta1</version> </dependency> Batch processing handlers
In previous releases, an extension handler typically processed events one at a time using CaptureEvent:
@ApplicationScoped public class CaptureHandler { @Capturing public void capture(CaptureEvent<SourceEvent, SourceEvent> event) { } } This works well for single-event processing, but doesn’t lend itself to scenarios where you need to operate across a batch of events.
Debezium 3.5 introduces the new CapturingEvents class for batch processing (debezium/dbz#1484):
@ApplicationScoped public class CaptureHandler { @Capturing public void capture(CapturingEvents<BatchEvent> events) { events.records().forEach(event -> event.commit()); } } This new contract is ideal for consumers that need to aggregate events or write to a target in bulk for optimal performance.
Debezium for CockroachDB
Initial snapshot support
The CockroachDB connector now supports snapshot.mode (debezium/dbz#1627). This allows users to snapshot or backfill historical data from the source database, just like other relational and non-relational connectors. The feature builds on the initial_scan behavior provided by CockroachDB’s change stream technology.
Multi-table concurrent streaming
In earlier builds, the CockroachDB connector created one change stream per table. While functional, CockroachDB recommends keeping the number of changefeed jobs below 80 per cluster — a limit that can be quickly reached in environments with many tables.
Debezium 3.5 introduces the ability to capture changes from multiple tables using a single changefeed job (debezium/dbz#1628). This aligns with CockroachDB’s recommended thresholds and improves overall throughput of the event capture process.
Debezium for Informix
Omit empty transaction metadata events
When provide.transaction.metadata is enabled, most consumers are only interested in transactions that contain events matching the connector’s include list.
Debezium 3.5 introduces cdc.return.empty.transactions, a configuration option that controls whether Informix returns empty transactions (debezium/dbz#1587). By default, empty transactions are omitted. To restore the previous behavior, set this option to true.
Debezium for Vitess
Improved transaction ordering with epoch
The Vitess connector can provide transaction order metadata to help downstream consumers process change events in the correct order. This is particularly important during operations like repartitioning.
In these cases, the epoch value needs to be incremented to ensure downstream consumers rank and order events correctly. Debezium 3.5 introduces vitess.connector.generation, a configuration property that can be increased when making changes that impact ordering semantics. Updating this value triggers an automatic epoch update on connector restart.
Other changes
-
Oracle database PDB name in lowercase not collecting DML operation [DBZ-9054] debezium/dbz#1057
-
A rolled back transaction mined in two steps sometimes leads to partial transaction id [DBZ-9686] debezium/dbz#1145
-
Avoid storing irrelevant DDL statement "REPLACE INTO" in schema history topic [DBZ-9428] debezium/dbz#1396
-
Connector cannot handle uncompressed transaction payloads beyond 2GB debezium/dbz#1503
-
Use platform add Destination has error type debezium/dbz#1505
-
When using default value for event.processing.failure.handling.mode (fail), data conversion exceptions are swallowed and the connector keeps on running debezium/dbz#1508
-
EventDeserializer composition in mysql-binlog-connector-java library should be fixed debezium/dbz#1518
-
Add support for ORIGIN Message in Postgresql Connector debezium/dbz#1528
-
Avoid overfetching of data for multi-tenant use cases debezium/dbz#1534
-
Implement value-based field dependencies in configuration API debezium/dbz#1542
-
Migrate schema generator to produce new descriptor format debezium/dbz#1543
-
Generate configuration descriptors for transforms, predicates, and sinks debezium/dbz#1544
-
Debezium Platform: Update Platform UI dev workflow to target backend URL at compile time debezium/dbz#1549
-
Change XStream outbound server property with adapter prefix debezium/dbz#1559
-
Log mining lower boundary does not update until a log switch debezium/dbz#1560
-
Stuck transaction when using CTE query with Oracle connector debezium/dbz#1564
-
Oracle Create Table DDL fails to parse when using
AUTOMATICkeyword in partition list debezium/dbz#1566 -
Implicit nullability in DDL (ALTER TABLE … CHANGE …) not respected by MySQL connector debezium/dbz#1568
-
"No enum constant io.debezium.connector.postgresql.connection.ReplicationMessage.Operation.NOOP" error when upgrading to Debezium 3.4.0 debezium/dbz#1574
-
ORA-03049 raised when querying archive logs debezium/dbz#1579
-
Move transformations and predicates to a dedicated module debezium/dbz#1583
-
Oracle DDL fails to parse debezium/dbz#1594
-
Debezium platform: Make the password field to mask the user entered text debezium/dbz#1598
-
Update Quarkus Extensions to Quarkus 3.31.3 debezium/dbz#1606
-
Update
mongodb-driver-syncto 5.6.2 debezium/dbz#1608 -
Add Podman example debezium/dbz#1609
-
Event loss when Kafka producer fails (e.g. delivery.timeout.ms exceeded) debezium/dbz#1610
-
Upgrade Testcontainers to 2.0.3 debezium/dbz#1615
-
Support
NodeSelectorandtolerationsin K8s CRDs with Debezium Operator debezium/dbz#1621 -
Update Informix JDBC Driver to v4.50.13 debezium/dbz#1623
-
Oracle Alter index Modify Subpartition Shrink DDL fails debezium/dbz#1637
-
Update debezium operator base image debezium/dbz#1645
Summary
In total, 72 issues were resolved in Debezium 3.5.0.Beta1. The list of changes can also be found in our release notes.
A big thank you to all the contributors from the community who worked diligently on this release:
Andrew Love, Andrew Ofisher, archie david, Archie David, Aviral Srivastava, Benoit Audigier, chirag-brevo, Chris Cranford, Duncan Prince, Filip Leski, gaurav miglani, Giovanni Panice, Gunnar Morling, Ian Muge, Issam El Nasiri, Jiang Zhu, Jiri Pechanec, Lars M. Johansson, Mario Fiore Vitale, Michael Terranova, Nathan Smit, Robert Roldan, Seongjun Shin, Shishir Sharma, Shiwanming, Thomas Thornton, Virag Tripathi