On this page

Last updated: April 23, 2026

Debezium Server

Debezium Server is an open-source (Apache 2.0) Change Data Capture engine that tails the write-ahead log of your source database and emits a structured event for every row-level change. On Guara Cloud it runs as a single Quarkus-based pod driven entirely by environment variables, with a JMX-to-Prometheus sidecar feeding the Insights tab.

Each deploy is one pipeline: one source connector, one sink, one replication slot. Event state (offsets and, for MySQL, schema history) lives on a per-service Longhorn volume at /debezium/data so restarts resume from the last committed position.

When to use Debezium

Debezium is the right choice when:

  • Your source is PostgreSQL, MySQL, or MongoDB and you need log-based CDC — every insert, update, and delete, in commit order, with near-zero lag on the source.
  • Your destination is NATS JetStream, Apache Kafka, or a generic HTTP webhook.
  • You want battle-tested snapshot + streaming semantics: an initial snapshot of existing rows followed by a seamless switch to streaming new changes.
  • You’re comfortable provisioning at least the Business tier — Debezium Server runs on the JVM and wants around 1 GiB of heap to handle non-trivial change rates.

Reach for Conduit instead when you want a Go runtime, need non-database sources (NATS, HTTP), or want to sink into another database.

Deploy walkthrough

  1. Provision the source and sink first. For a sibling-mode flow, deploy a PostgreSQL catalog service (source) and a NATS catalog service (sink), and wait for both to show Running. External sources and sinks do not need this step.
  2. Open the catalog wizard. From your project dashboard, click New Service, select the Service Catalog tab, and choose Debezium.
  3. Choose the version. Three tags are available: 3.5.0.Final (default), 3.4.3.Final, and 3.3.1.Final. Stay on the default unless you have a specific reason to pin an older release.
  4. Configure the source.
    • sourceKind — pick PostgreSQL, MySQL, or MongoDB.
    • sourceModeSibling catalog service to pick another service in the project, or External URL to point at a database off-platform.
    • sourceServiceSlug — shown only in sibling mode, the picker lists every matching catalog service already in the project.
    • sourceExternalUrl — shown only in external mode, paste a full JDBC-style URL (for example postgresql://host:5432/appdb or mongodb://host:27017/appdb).
    • tableFilter — optional. Comma-separated schema.table list to restrict capture; public.orders,public.customers captures just those two tables. For MongoDB the same field filters collections.
    • topicPrefix — optional. Prefix applied to every emitted topic/subject; defaults to the service slug when blank.
  5. Configure the sink.
    • sinkKindNATS JetStream, Apache Kafka, or HTTP webhook.
    • sinkModeSibling (for a sibling NATS) or External (for Kafka, HTTP, or an external NATS).
    • sinkServiceSlug — the sibling picker, restricted to NATS catalog services.
    • sinkExternalUrl — paste a full URL: bootstrap servers for Kafka, the webhook URL for HTTP.
  6. External credentials. When either side is external, the wizard shows four additional fields — sourceExternalUsername, sourceExternalPassword, sinkExternalUsername, sinkExternalPassword. These are stored in the service’s encrypted Secret and mapped to SOURCE_EXTERNAL_* / SINK_EXTERNAL_* env vars inside the pod.
  7. Deploy. Click Deploy. Debezium takes 45–90 seconds to reach Ready on the first boot while Quarkus warms up and the initial snapshot starts.

Insights tab

The Insights tab renders panels fed by a bitnami/jmx-exporter sidecar that scrapes Debezium’s JMX MBeans on pod-local loopback (port 1099) and republishes them as Prometheus metrics on :9404/metrics. Panels are grouped into two sections:

Replication Health

  • Replication Lag — gauge, seconds behind the source database. Derived from debezium_milli_seconds_behind_source / 1000. Under 30s is the comfort zone; sustained values above 60s mean the sink is back-pressuring or the source is emitting faster than Debezium can process.
  • Last Event Timestamp — table, Unix timestamp of the most recent event. A flat value over several minutes when the source is actively changing signals a stuck pipeline.
  • Snapshot Progress — gauge, percentage of the initial snapshot completed. Derived from debezium_rows_scanned / debezium_total_number_of_rows_scanned. You want this to climb monotonically from 0 to 100% on the first boot and stay at 100% afterwards.

Throughput

  • Events/sec — area, 1-minute rate of debezium_total_number_of_events_seen. Your baseline depends on write volume — the shape (spikes, plateaus, drops) is what you read.
  • Events Filtered — stacked area, 5-minute rate of events discarded by include/exclude rules. Useful for verifying tableFilter is doing what you expect.
  • Queue Remaining — gauge, free slots in the internal queue (debezium_queue_remaining_capacity). Dropping near zero means the sink can’t keep up.

Troubleshooting

Replication slot not cleaned up after delete

Deleting a Debezium service tears down the pod and its PVC, but the replication slot on the source PostgreSQL stays — and a retained slot holds WAL files forever, which will fill the source’s disk.

Always clean up by hand after deletion:

-- Run against the SOURCE PostgreSQL, not the Debezium pod
SELECT pg_drop_replication_slot('guara_slot_YOUR_SERVICE_SLUG');

The slot name pattern is guara_slot_<serviceSlug> with - replaced by _. You can list live slots with SELECT slot_name, active FROM pg_replication_slots; before dropping.

Snapshot stuck on a large table

The initial snapshot runs SELECT * against every included table. On tables above a few million rows the first pass can take minutes and looks stuck in the Insights tab. Watch Snapshot Progress — if it’s climbing, wait; if it’s flat for more than 10 minutes at the same value, check the source for lock contention (another process holding the table).

Restarting the pod resumes snapshot from the last committed offset, not from zero, so a failed snapshot over a large table is not a do-it-all-again situation.

Schema changes during a snapshot

Debezium captures a schema on snapshot start and expects it to stay stable until streaming begins. A DDL change mid-snapshot (column renamed, type changed) can corrupt the in-progress snapshot. Wait for Snapshot Progress to reach 100% before running migrations, or drop the replication slot and restart Debezium to re-snapshot.

Resource sizing on the Pro tier

Debezium Server runs on Quarkus, and the Pro tier’s 512 MiB memory ceiling is enough for smoke tests and demos only. For any production-grade change rate, provision at the Business tier (1–2 GiB heap) or above. The catalog wizard lets you deploy on Pro for evaluation, but do not run a production OLTP source against a Pro-sized Debezium pod.

External Kafka with SASL/SSL

When sinkKind=Apache Kafka in external mode, paste the bootstrap-servers URL in sinkExternalUrl and the SASL credentials in sinkExternalUsername / sinkExternalPassword. Debezium negotiates the protocol (PLAINTEXT, SASL_PLAINTEXT, SASL_SSL) based on what the broker advertises; no extra configuration is needed for standard SASL/SCRAM or SASL/PLAIN deployments. If you need client-certificate auth, raise a support request — that path needs a custom truststore mount that v1 doesn’t surface in the wizard.

External PostgreSQL refuses to replicate

Three settings on the source have to be right:

  • wal_level = logical in postgresql.conf (requires a restart).
  • The connecting role has both LOGIN and REPLICATION attributes.
  • max_replication_slots and max_wal_senders are each at least 1 higher than the number of CDC consumers — Debezium consumes one slot per service.

Guara-managed PostgreSQL sets all three automatically; external databases need the administrator to apply them.

Upstream resources

Next steps