sysadmin and no access to the transaction log. That makes it the method to use when CDC cannot be enabled, for example on Express edition, on Azure SQL Database tiers without CDC, or when the DBA will not grant elevated rights.
Its events use the same Debezium envelope and the same topic layout (<prefix>.<database>.<schema>.<table>) as the other SQL Server sources, so existing data models and targets work unchanged.
In the Popsink UI, pick the SQL Server tile, then Change Tracking as the capture method.
Choosing a capture method
What it captures
Change Tracking records which primary key changed, how, and at which version, never the row’s values. The connector reads each changed row back from the table. As a result:- Net changes only. A row updated several times between two polls arrives once, with its latest values. Intermediate states are not captured.
- No before-image. An update carries
before = null. A delete carries the primary key columns only. - The after-image is the row as the connector reads it, not as it was at commit time.
What two polls can see:
A target must therefore accept a
d for a key it does not hold. Every Popsink target does.
source.ts_ms is the commit time of the change when the login holds the optional commit-time right (see Permissions). Without it, recent changes carry the time they were read instead.
What is not captured
Column types
Types are published as the CDC source publishes them. Worth knowing:Compatible versions
Prerequisites
1. Enable Change Tracking on the database
- Retention: at least 3 days, and always longer than the longest connector downtime you expect. A connector stopped longer than the retention cannot read what changed in between (see Retention gap).
- Keep
AUTO_CLEANUP = ON, otherwise the internal change tables grow without bound.
2. Allow snapshot isolation
The connector reads each batch inside oneSNAPSHOT transaction. Without it, every read fails (error 3952).
- the statement waits for every open transaction in the database to finish: run it in a quiet window;
- from then on,
UPDATEandDELETEkeep row versions intempdbwhile a snapshot transaction may need them, and add 14 bytes to each updated row. Sizetempdbaccordingly.
3. Enable Change Tracking on each table
Every captured table needs a primary key.TRACK_COLUMNS_UPDATED is not needed: the connector reads the whole row.
Permissions
Nothing else: no
db_owner, no sysadmin, no write access. The connector never writes to the source.
- SQL Server, Managed Instance, RDS
- Azure SQL Database
On Amazon RDS, the master user may be refused
VIEW SERVER PERFORMANCE STATE on 2022+. Grant VIEW SERVER STATE instead. The commit-time right is optional: without it the connector still runs.Checking the prerequisites
Test Credentials checks the database prerequisites and lists each one that is not met, with the statement that fixes it. The table picker then greys out each table missing a prerequisite of its own (primary key, Change Tracking,SELECT, VIEW CHANGE TRACKING).
Configuration
Connecting through an SSH Tunnel
If the database is only reachable through a bastion host, enable SSH Tunnel and provide:
The Host and Port above stay as the database is addressed from the
bastion. For key generation, bastion hardening and the other connectivity
options (IPsec VPN, Tailscale), see
Tunnels and private connectivity.
Initial load
The initial load runs in chunks of 10,000 rows, read in primary-key order, while the table already streams. Each chunk is its own short snapshot transaction, sotempdb and Change Tracking cleanup are held for one chunk, not for the whole table, and the other tables keep streaming meanwhile. The same chunked read runs for a table added to the whitelist later. Snapshot rows carry op = r.
A table whose primary key contains a datetimeoffset, sql_variant or hierarchyid column cannot be read in chunks. It is read in one snapshot transaction before streaming starts: size tempdb for it or start the connector in a quiet window.
Load on the source
- Every write to a captured table adds one row to that table’s internal change table, a cost Microsoft compares to maintaining one more index.
- Snapshot isolation adds the
tempdbversion store and 14 bytes per updated row, database-wide. - Each poll runs one
CHANGETABLEquery per captured table, then reads the changed rows by primary key. Its cost follows the number of rows changed since the last poll, not the size of the table. A backlog is read in pages, so catching up after a pause does not slow down as it drains.
Retention gap
A connector stopped longer than the Change Tracking retention can no longer read what changed. It stops with an error naming the affected tables, without a restart loop: nothing is lost silently. ATRUNCATE TABLE on a captured table has the same effect.
To recover, reload the affected tables with an incremental load through the API.
Reloading tables
The UI offers no reload for this source. Trigger an incremental load through the API: the selected tables are read again in chunks while the change stream keeps flowing, and every subscriber of the connector’s topics receives the rows.409; follow the running load with GET /connectors/{connector_id}/incremental-load-status.