Skip to main content
Materialize can ingest data from PostgreSQL (11+) databases using PostgreSQL’s native logical replication protocol for Change Data Capture (CDC). This allows you to continuously stream INSERT, UPDATE, and DELETE operations from your PostgreSQL database into Materialize.

Prerequisites

Before creating a PostgreSQL source, you must:
  1. Enable logical replication in your PostgreSQL database
  2. Create a publication for the tables you want to replicate
  3. Create a dedicated replication user with appropriate permissions
  4. Configure network access to allow Materialize to connect
Logical replication must be enabled before you can create a PostgreSQL source. This typically requires a database restart.

Step 1: Configure PostgreSQL

Enable Logical Replication

  1. Check if logical replication is enabled:
-- In PostgreSQL
SHOW wal_level;
  1. If wal_level is not set to logical, update your postgresql.conf:
wal_level = logical
  1. Restart PostgreSQL for the change to take effect.

Create a Publication

Create a publication for the tables you want to replicate:
-- In PostgreSQL: Create publication for specific tables
CREATE PUBLICATION mz_source FOR TABLE table1, table2, table3;

-- Or for all tables in the database
CREATE PUBLICATION mz_source FOR ALL TABLES;

Create a Replication User

Create a dedicated user with replication permissions:
-- In PostgreSQL
CREATE USER materialize WITH REPLICATION PASSWORD '<password>';

-- Grant permissions on the publication
GRANT SELECT ON table1, table2, table3 TO materialize;
GRANT USAGE ON SCHEMA public TO materialize;

-- For all tables in a schema
GRANT SELECT ON ALL TABLES IN SCHEMA public TO materialize;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT ON TABLES TO materialize;

Step 2: Configure Network Security

Choose a network security option based on your deployment:

Step 3: Create a Connection in Materialize

CREATE SECRET pgpass AS '<POSTGRES_PASSWORD>';

CREATE CONNECTION pg_connection TO POSTGRES (
    HOST 'instance.foo000.us-west-1.rds.amazonaws.com',
    PORT 5432,
    USER 'materialize',
    PASSWORD SECRET pgpass,
    SSL MODE 'require',
    DATABASE 'postgres'
);

Step 4: Create a Source

Create subsources for all tables in the publication:
CREATE SOURCE pg_source
    FROM POSTGRES CONNECTION pg_connection
    (PUBLICATION 'mz_source')
    FOR ALL TABLES;

Handling Unsupported Types

If your tables contain unsupported data types, use the TEXT COLUMNS option:
CREATE SOURCE pg_source
    FROM POSTGRES CONNECTION pg_connection (
        PUBLICATION 'mz_source',
        TEXT COLUMNS (table_name.column_with_unsupported_type)
    )
    FOR ALL TABLES;

How It Works

Replication Slots

Materialize automatically creates a replication slot in PostgreSQL for each source. The replication slot name is prefixed with materialize_ for easy identification.
-- Find the replication slot name
SELECT id, replication_slot
FROM mz_internal.mz_postgres_sources;
   id   |             replication_slot
--------+----------------------------------------------
  u8     | materialize_7f8a72d0bf2a4b6e9ebc4e61ba769b71
Each source uses a single replication slot for all tables in the publication, minimizing the performance impact on PostgreSQL.

Subsources

Materialize automatically creates a subsource for each table in the publication:
SHOW SOURCES;
         name         |   type
----------------------+-----------
 pg_source            | postgres
 pg_source_progress   | progress
 users                | subsource
 orders               | subsource
 products             | subsource

Progress Tracking

Monitor ingestion progress using the progress subsource:
SELECT lsn
FROM pg_source_progress;
The lsn (Log Sequence Number) should increase as Materialize consumes new WAL records from PostgreSQL.

Monitoring

Check Source Status

SELECT *
FROM mz_internal.mz_source_statuses
WHERE name = 'pg_source';

Monitor Snapshotting Progress

SELECT
    name,
    snapshot_committed,
    bytes_received,
    messages_received
FROM mz_internal.mz_source_statistics s
JOIN mz_sources src ON s.id = src.id
WHERE src.name = 'pg_source';

Monitor Replication Lag

In PostgreSQL, check replication slot lag:
-- In PostgreSQL
SELECT
    slot_name,
    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS lag
FROM pg_replication_slots
WHERE slot_name LIKE 'materialize_%';

Schema Changes

Compatible Changes

Materialize automatically handles these schema changes:
  • Adding a column with a DEFAULT value
  • Adding a nullable column
  • Dropping a column
  • Changing column default values

Incompatible Changes

These changes require manual intervention:
  • Changing a column’s data type
  • Adding a NOT NULL constraint
  • Renaming columns or tables
To handle incompatible changes:
-- 1. Drop the affected subsource
DROP SOURCE users;

-- 2. Add it back to the source
ALTER SOURCE pg_source ADD SUBSOURCE users;

Handling Errors

Source in Error State

Check the error message:
SELECT error
FROM mz_internal.mz_source_statuses
WHERE name = 'pg_source';
Common issues:
  • Replication slot deleted: Recreate the source
  • Connection refused: Check network security settings
  • Authentication failed: Verify credentials and permissions
  • Publication not found: Ensure the publication exists in PostgreSQL

Adding Subsources After Errors

After fixing schema issues:
-- List all subsources
SHOW SUBSOURCES ON pg_source;

-- Drop the errored subsource
DROP SOURCE table_name;

-- Add it back with the updated schema
ALTER SOURCE pg_source ADD SUBSOURCE table_name;

Best Practices

Resource Management

Create a dedicated cluster for PostgreSQL sources:
CREATE CLUSTER postgres_ingest SIZE = '100cc';

SET CLUSTER = postgres_ingest;

CREATE SOURCE pg_source FROM ...
For large initial snapshots, use a larger cluster temporarily:
-- Before creating the source
ALTER CLUSTER postgres_ingest SET (SIZE = '200cc');

-- After snapshotting completes
ALTER CLUSTER postgres_ingest SET (SIZE = '100cc');

Limit Data Volume

  • Create publications for specific tables, not all tables
  • Use schema filtering to limit subsources
  • Only replicate tables you need in Materialize

Publication Management

If you add or remove tables from the PostgreSQL publication, Materialize will not automatically detect these changes. You must manually add or drop subsources.

WAL Retention

Ensure PostgreSQL retains WAL files long enough:
-- In PostgreSQL
SHOW wal_keep_size;  -- or wal_keep_segments for older versions
If Materialize is offline for too long, the replication slot may fall behind and you’ll need to recreate the source.

Troubleshooting

Source Not Progressing

Check replication slot status in PostgreSQL:
-- In PostgreSQL
SELECT
    slot_name,
    active,
    restart_lsn,
    confirmed_flush_lsn
FROM pg_replication_slots
WHERE slot_name LIKE 'materialize_%';
Check for replication conflicts:
-- In PostgreSQL
SELECT * FROM pg_stat_replication;

High Memory Usage

For tables with large row sizes or high update rates:
  1. Increase cluster size
  2. Limit columns using table-specific filtering
  3. Consider using separate sources for high-volume tables

Snapshotting Takes Too Long

  1. Scale up the cluster temporarily during snapshotting
  2. Reduce data volume by limiting tables or using filters
  3. Run during off-peak hours to minimize database load
  4. Monitor progress using mz_source_statistics

Connection Issues

Test connectivity from Materialize:
-- This will fail if there are connectivity issues
VALIDATE CONNECTION pg_connection;
Common solutions:
  • Verify firewall rules allow connections from Materialize IPs
  • Check that SSL/TLS settings match PostgreSQL configuration
  • Ensure the database user has replication permissions
  • Verify the PostgreSQL server is accepting replication connections

Supported PostgreSQL Services

Materialize supports PostgreSQL CDC from:
  • Amazon RDS for PostgreSQL
  • Amazon Aurora PostgreSQL
  • Google Cloud SQL for PostgreSQL
  • Azure Database for PostgreSQL
  • Self-hosted PostgreSQL
  • AlloyDB for PostgreSQL
  • Neon
Some managed PostgreSQL services require additional configuration steps. Consult your provider’s documentation for enabling logical replication.

Next Steps

Transform Data

Create materialized views on your PostgreSQL data

MySQL CDC

Learn about ingesting data from MySQL

Build docs developers (and LLMs) love