How to Optimize Immich Database Connections for Concurrent Containers

Eva Wong is the Technical Writer and resident tinkerer at ZimaSpace. A lifelong geek with a passion for homelabs and open-source software, she specializes in translating complex technical concepts into accessible, hands-on guides. Eva believes that self-hosting should be fun, not intimidating. Through her tutorials, she empowers the community to demystify hardware setups, from building their first NAS to mastering Docker containers.

Optimize Immich database connections by measuring the total session demand across every Immich process and other PostgreSQL client, not by raising max_connections first. The database needs enough sessions for the real workload plus administrative headroom, but excessive concurrency can increase memory use and contention without making queries faster.

On a multi-container home server, record active, idle, and waiting connections together with query latency, CPU, memory, and storage latency during normal use and during simultaneous startup. A โ€œtoo many clientsโ€ error can come from aggregate configuration, another service, or a restart storm even when one Immich container appears modest.

Inventory Every PostgreSQL Client Before Changing Limits

List each Immich server process or replica, migration/maintenance task, backup job, monitoring tool, and unrelated application that connects to the same PostgreSQL instance. Give them separate database users where practical so pg_stat_activity can show who holds sessions. Record current max_connections and preserve one administrative route for incident response.

An Immich โ€œtoo many clientsโ€ discussion includes a project comment that Immich used a default pool of 10 in that release. A separate 2026 discussion notes multiple Immich workers can each maintain a pool. Treat these figures as version-specific implementation context, not a number to multiply blindly across future releases. If the database is already near its connection ceiling while Immich is idle, identify the owner of those sessions before tuning Immich. If active sessions are few but queries are slow, connection count may be a symptom of storage or query latency rather than the primary bottleneck.

Build a Connection Budget From Measured Concurrency

Reserve sessions for database administration, backup/restore tooling, migrations, and monitoring.

Then budget the remaining application connections across the number of simultaneously running Immich processes and other applications. The goal is a pool large enough that normal work does not wait unnecessarily, but no larger than the database can execute efficiently.

A PostgreSQL connection-pool sizing analysis describes the ideal pool as large enough for normal demand while remaining as small as practical, because fewer backend sessions reduce contention. Apply that principle to observed Immich demand instead of copying a web-server pool size from another workload.

If the Immich release does not expose a supported pool-size control, do not patch internals simply to hit a target number. Control what you can: number of application replicas, unrelated clients, restart timing, backup overlap, and database capacity. Re-evaluate supported configuration when versions change.

Reduce Connection Churn and Database Waiting Before Adding More Sessions

Stagger container startup so Immich, analytics, backup jobs, and other apps do not all reconnect or migrate simultaneously. Use health/readiness checks that wait for PostgreSQL to be usable, but avoid tight retry loops that create a connection storm while the database is still recovering.

The ZimaSpace guide to external Immich database safety is an important boundary: once PostgreSQL is separated from the default stack, version, extension, privilege, backup, and rollback responsibilities become explicit. A connection proxy or extra database host should not be introduced solely to hide slow queries or saturated storage.

If many sessions are idle and application count is legitimately high, a connection pooler can reduce backend sessions in some PostgreSQL architectures, but only after testing the exact Immich version, migrations, transaction semantics, and prepared-statement behavior. Pooling is not a substitute for correcting a runaway client or an overloaded database.

Validate With Concurrent Upload, Search, Jobs, and Restart

Build a repeatable peak: run representative mobile uploads, an older search or browse action, and the normal background job mix while other expected containers are active. Record connection count by user/state, acquisition or request errors, query latency, database CPU, memory, and disk latency. Then repeat after one change.

A passing configuration keeps sessions below the failure ceiling with administrative headroom, avoids โ€œtoo many clientsโ€ errors, keeps query latency inside the household target, and allows queues to drain after the peak. More connections are justified only when requests are genuinely waiting for a session while the database still has CPU, memory, and I/O capacity.

Restart the application stack and then the host once to test the highest connection burst. If the failure appears only during startup, fix ordering/retry behavior rather than raising the permanent ceiling. If sessions accumulate over time, capture the owning users and queries and escalate that leak pattern with versions and connection-state evidence.

Support & Tips

More to Read

Get More Builds Like This

Stay in the Loop

Get updates from Zima - new products, exclusive deals, and real builds from the community.

Stay in the Loop preferences

We respect your inbox. Unsubscribe anytime.