mysql
watcher

MySQL Setup

CDC Watcher uses MySQL binlog replication — the same mechanism as Debezium. No special table schema needed.

Server Configuration

# my.cnf
log_bin          = ON
binlog_format    = ROW
binlog_row_image = FULL
server_id        = 1

Pre-configured in the provided docker-compose.yml. For an existing MySQL instance, add these to my.cnf and restart.

User Privileges

GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'user'@'%';
FLUSH PRIVILEGES;

DDL Capture

MySQL captures DDL changes (CREATE, ALTER, DROP) automatically via QUERY binlog events — no extra configuration needed. DDL events are published with type: "DDL".

Snapshot Mode

Capture existing rows before streaming live changes:

# Options: none (default), initial, schema_only
app.cdc.mysql.snapshot-mode=initial
ModeBehavior
noneOnly capture changes from now on
initialSnapshot all existing rows on first start, then stream changes
schema_onlyCapture schema structure only, then stream changes

Offset Persistence

MySQL binlog position is persisted automatically via NATS JetStream. On restart, the watcher resumes from the last acknowledged offset — no manual tracking needed.

Type Mapping

MySQL types are mapped to JSON-friendly values:

MySQL TypeJSON Output
DATE, DATETIME, TIMESTAMPISO 8601 string ("2026-03-25T08:30:00Z")
DECIMAL, NUMERICJSON number (99.99)
TINYINT(1) / BOOLEANJSON boolean (true / false)
BLOB, BINARYBase64-encoded string
ENUMString value ("active")
All othersString

Table Filtering

Watch specific tables instead of all:

# Comma-separated list (empty = watch all tables)
app.cdc.mysql.tables=orders,products,customers

Full Application Config

# Database connection
app.cdc.mysql.url=jdbc:mysql://localhost:3306/mydb
app.cdc.mysql.username=user
app.cdc.mysql.password=secret

# CDC settings
app.cdc.mysql.enabled=true
app.cdc.mysql.tables=
app.cdc.mysql.snapshot-mode=none
app.cdc.mysql.server-id=1

# NATS
app.cdc.nats.url=nats://localhost:4222
app.cdc.nats.stream-name=cdc-stream

Example Events

MySQL uses real column names:

[CDC] INSERT table=products data={"id": 1, "name": "laptop", "price": 999.99, "stock": 10}
[CDC] UPDATE table=products data={"old": {"price": 999.99}, "new": {"price": 949.99}}
[CDC] DELETE table=products data={"id": 2, "name": "phone", "price": 499.50}
[CDC] DDL   table=products data={"ddl": "ALTER TABLE products ADD COLUMN category VARCHAR(50)"}

PostgreSQL vs MySQL Comparison

CapabilityPostgreSQL (WAL)MySQL (binlog)
INSERTFull rowFull row
UPDATENew only (default), old+new with REPLICA IDENTITY FULLFull old + new row (always)
DELETEPK only (default), full row with REPLICA IDENTITY FULLFull deleted row (always)
DDLcapture-ddl=trueAutomatic
Column namesReal names (RELATION message)Real names
LatencyReal-timeReal-time
DB setupwal_level=logicallog_bin=ROW
Offset trackingReplication slot (automatic)NATS JetStream (automatic)