Tuning PostgreSQL and Connection Pooling for Matrix Synapse

Scaling a decentralized chat backend alongside a traditional discussion board requires a solid database strategy. While default settings function adequately for early testing, high-volume federated rooms place sustained pressure on database workers. Community administrators deploying a Synapse Matrix homeserver need to understand how the Twisted adbapi connection pool interacts with PostgreSQL, which memory dials impact maintenance routines, and how vacuum processes keep disk bloat under control.
Why should administrators transition Synapse from SQLite to PostgreSQL?
Early community deployments often launch on SQLite, but growing installations hit concurrency boundaries quickly. The official migration utility, synapse_port_db, transfers database states in a two-stage process using database snapshots while preventing data loss. When planning this transition, administrators must budget for storage expansion: the database can occupy 25% to 100% more space on disk after migrating to PostgreSQL.
During setup, the target database must be instantiated with precise character encoding and collations. Creating the database requires specific parameters:
- A designated user such as
synapse_usercreated via the command line. - A database generated with
--encoding=UTF8,--locale=C, and--template=template0.
As outlined in the Synapse documentation on Using Postgres, PostgreSQL must have the proper encoding set to guarantee reliable storage of UTF8 strings across active chat rooms.
How does Twisted adbapi connection pooling operate in Synapse?
Synapse establishes its database connectivity through the psycopg2 driver managed by a Twisted adbapi connection pool. In your configuration file, connection boundaries are defined within the database.args section. Parameters prefixed with cp_ are consumed directly by the connection pool rather than forwarded to the database driver itself.
A standard configuration establishes minimum and maximum pool limits:
cp_min: 5sets the floor for active pooled connections maintained by the process.cp_max: 10caps the maximum concurrent connections Twisted will open for that worker.
Any non-prefixed values placed in the args mapping pass straight to the underlying connection function, allowing administrators to supply standard connection flags supported by the database driver.
Why are TCP keepalive arguments critical for pool stability?
If network routing between your Matrix homeserver and the database cluster drops unexpectedly, Synapse risks blocking for an extended period while awaiting responses. You can prevent orphaned sessions and silent connection drops by tuning TCP keepalive settings within the database.args configuration block:
keepalives_idle: 10specifies seconds of inactivity before sending a keepalive message over the TCP session.keepalives_interval: 10sets the number of seconds to wait before retransmitting an unacknowledged keepalive probe.keepalives_count: 3establishes how many consecutive keepalive probes can be lost before the client considers the connection dead.
Configuring these values ensures dropped connections are caught promptly, allowing the pool to terminate stalled handles and establish fresh sockets without manual restarts.
Which PostgreSQL memory parameters influence autovacuum and throughput?
High transaction throughput creates dead row versions from constant updates, event receipts, and presence updates. To support intensive workloads, several system directives should be reviewed based on available free memory on your host:
shared_buffers: determines dedicated shared memory allocated for caching table and index pages.effective_cache_size: guides the query planner on overall memory available for caching.work_mem: controls internal sort operations and hash tables per query.maintenance_work_mem: allocates working memory for vacuuming and maintenance tasks.autovacuum_work_mem: specifically assigns memory limits to background autovacuum workers.
According to the official Using Postgres documentation for Synapse, tuning these fields depends on the host's free memory, and administrators operating very large shared buffers may also evaluate huge pages to assist operating system memory management.
How do standard VACUUM routines prevent table bloat?
Under PostgreSQL's multiversion concurrency control model, updating or deleting rows leaves dead row versions behind until cleaned. Routine vacuuming handles four essential responsibilities: reclaiming dead row storage for future use, updating query planner statistics, refreshing the visibility map for index-only scans, and protecting against transaction ID or multixact ID wraparound failures.
Administrators must distinguish standard vacuuming from manual compaction. Standard vacuuming operates concurrently alongside regular operations like SELECT, INSERT, UPDATE, and DELETE. It frees space inside pages for future rows without locking the table. Conversely, VACUUM FULL demands an ACCESS EXCLUSIVE lock, builds a brand-new copy of the table file, and consumes extra disk space during processing. Relying on routine background passes avoids reaching table states that demand exclusive downtime locks.
What safety checks are necessary before major database upgrades?
Major PostgreSQL version upgrades store data in distinct directories, typically following the path /var/lib/postgresql/<version>/main. Before performing major upgrades, shut down Synapse and related backend services such as authentication services. Most importantly, always back up your forum and homeserver databases beforehand to prevent catastrophic data loss if the migration fails.
Sources
Published October 30, 2026. No affiliate links on this page. Facts come from the sources linked above; check them for updates.