Dieser Artikel enthält die vom PostgreSQL-Wiki veröffentlichte Formel zur Berechnung der idealen Parallelität Ihrer Hardware (die am häufigsten zitierte Verbindungspool-Größenformel im Ökosystem), erklärt, warum jede Verbindung mehr kostet als ein Anwendungsthread, und beschreibt dann die Vorgehensweise zum Festlegen von max_connections ohne zu raten. Unsere Benchmark-Methodik dokumentiert das Messprotokoll, das für alle Leistungsansprüche in diesem Blog verwendet wird.
Das Wesentliche
- Ohne Pooling sollte max_connections alle gleichzeitigen Clientverbindungen abdecken, nicht nur diejenigen, die Postgres effizient parallel verarbeiten kann.
- PostgreSQL-Wiki-Referenzformel: ideale aktive Parallelität = (physische Kerne × 2) + effiziente Festplatten. Ein durch Messung zu validierender Ausgangspunkt, keine feste Grenze.
- max_connections ist ein
postmaster-Kontextparameter: Für seine Änderung ist ein vollständiger Neustart des Servers erforderlich, kein einfaches Neuladen. - Jede Postgres-Verbindung ist ein separater Systemprozess und kein leichtgewichtiger Thread: Dies macht den Overhead deutlich, sobald die Anzahl der Verbindungen steigt.
- Im Code verifiziert: Auf seinen dedizierten Postgres-Clustern variiert Aurabase max_connections von 50 (kostenlose Stufe) bis 400 (Enterprise-Stufe), abhängig von der Größe des Clusters.
Warum eine Postgres-Verbindung mehr kostet als ein Anwendungsthread
Postgres verwendet für seine Verbindungen keinen Lightweight-Thread-Pool. Jede Client-Verbindung löst einen vollwertigen Systemprozess aus.
Der postmaster-Prozess erstellt für jeden Verbindungsversuch einen neuen („Fork“), der dieser einzelnen Sitzung gewidmet ist, bis sie geschlossen wird. Die offizielle Projektdokumentation beschreibt genau diesen Mechanismus in ihrem Kapitel über Architekturgrundlagen (postgresql.org/docs/current/connect-estab.html, Abschnitt „Verbindungssemantik“, abgerufen am 24. August 2026).
Diese Wahl hat einen echten Vorteil: Ein Absturz einer Verbindung hat keine Auswirkungen auf die anderen, da jeder Prozess vom Rest des Servers isoliert ist. Es verursacht auch direkte Kosten: Jede zusätzliche Verbindung fügt einen gesamten Betriebssystemprozess zur Planung hinzu, mit eigenem Speicherplatz und eigenem Kontextwechsel-Overhead für den Kernel.
Eine Anwendung, die 500 direkte Verbindungen zu Postgres ohne Pooling öffnet, zwingt den Server, 500 gleichzeitige Systemprozesse zu verwalten, selbst wenn die überwiegende Mehrheit davon zwischen zwei Anfragen inaktiv bleibt.
Zwei unterschiedliche Mechanismen wirken sich auf das Gedächtnis aus und ihre Verwechslung führt fast immer zu einer Fehldiagnose.
Das erste ist behoben. Beim Start reserviert Postgres gemeinsam genutzte Speicherstrukturen (Sperren, Prozesstabelle), deren Größe dem Wert von max_connections entspricht, unabhängig davon, ob diese Verbindungen anschließend geöffnet werden oder nicht. In der offiziellen Dokumentation der Einstellung wird ausdrücklich darauf hingewiesen, dass eine Erhöhung möglicherweise mehr gemeinsam genutzten Systemspeicher erfordert, als die Standardkonfiguration Ihres Betriebssystems zulässt (postgresql.org/docs/current/runtime-config-connection.html, abgerufen am 24. August 2026).
Die zweite Möglichkeit ist variabel und im Maßstab viel gefährlicher: work_mem wird nicht einmal pro Verbindung zugewiesen, sondern einmal pro Sortier- oder Hashing-Vorgang im Abfrageplan. Die offizielle Dokumentation ist in diesem Punkt explizit: Eine komplexe Abfrage kann mehrere dieser Vorgänge parallel starten, und mehrere Sitzungen können dasselbe gleichzeitig tun, sodass der tatsächlich verwendete Speicher ein Mehrfaches von work_mem wert sein kann (postgresql.org/docs/current/runtime-config-resource.html, abgerufen am 24. August 2026).
Es ist nicht allein max_connections × work_mem, das den Speicher eines Servers bedroht. Es ist max_connections × work_mem × Anzahl gleichzeitiger Vorgänge pro Abfrage. Es ist dieses Produkt, das einen Server erklärt, der nach einer als harmlos angesehenen Erhöhung der max_connections auswechselt oder ihm der Speicher ausgeht.
Die PostgreSQL-Wiki-Größenformel
Das offizielle PostgreSQL-Projekt-Wiki dokumentiert eine Benchmark-Formel zur Berechnung, wie viele aktive -Verbindungen Ihre Hardware effizient parallel verarbeiten kann, und nicht, wie viele Verbindungen insgesamt geöffnet sind (wiki.postgresql.org/wiki/Number_Of_Database_Connections, abgerufen am 24. August 2026).
ideale aktive Parallelität = (physische Kerne × 2) + effiziente Festplatten. Die Anzahl der Kerne schließt Hyperthreading aus. Die Anzahl der effektiven Festplatten bleibt bei modernen SSD-Speichern nahe bei 1, wobei der Begriff einer separaten physischen Festplatte („Spindel“) viel von seiner ursprünglichen Bedeutung verliert.
Auf einem Server mit 8 physischen Kernen und SSD-Speicher ergibt die Formel (8 × 2) + 1 = 17 aktive Verbindungen, bevor der Durchsatz nachzulassen beginnt. Diese Zahl ist oft überraschend: Im Vergleich zu den Hunderten von Verbindungen, die eine Anwendung in der Praxis öffnet, erscheint sie winzig. Genau darum geht es im folgenden Absatz.
Die durch die Formel berechnete Zahl misst die Parallelität, die die CPU und die Festplatte aufnehmen können, und nicht die Anzahl der Clientverbindungen, die Ihre Anwendung öffnen muss. Eine Flotte von 20 Anwendungsprozessen, von denen jeder über einen eigenen Pool von 10 Verbindungen verfügt, öffnet 200 gleichzeitige Verbindungen zu Postgres, auch wenn jeweils nur 17 davon aktiv arbeiten. Ohne Pooler muss max_connections die 200 abdecken, nicht die 17. Es ist diese Lücke, die die meisten Architekturen dazu drängt, einen -Pooler im Transaktionsmodushinzuzufügen, auch wenn das bedeutet, dass man sich für einen entscheiden muss (siehe unseren -Vergleich PgBouncer, Supavisor und PgCat).
So ändern Sie max_connections (und warum ein Neustart erforderlich ist)
max_connections wird nicht im laufenden Betrieb ausgetauscht. Dies ist ein postmaster-Kontextparameter: Postgres liest ihn einmal beim Start, um die Größe seines gemeinsam genutzten Speichers zu bestimmen. Ein Neuladen der Konfiguration (pg_reload_conf() oder SIGHUP) reicht nicht aus, Sie müssen den Server neu starten.
Überprüfen Sie zunächst den aktuellen Wert und seinen Kontext, um sicherzustellen, dass ein Neustart erforderlich ist:
Wenden Sie dann den neuen Wert an und starten Sie neu:
max_connections enthält standardmäßig superuser_reserved_connections (standardmäßig 3): Diese Verbindungen sind im Falle einer Sättigung für einen Superuser reserviert, sie sind für Ihre Anwendung nie verfügbar, auch wenn der globale Zähler noch nicht erreicht ist.
Wie Aurabase max_connections auf seinen Postgres-Clustern budgetiert
Die Dimensionierung von max_connections ist nicht nur eine theoretische Übung. So budgetiert Aurabase seine verwalteten Postgres-Cluster:
Dedizierte Cluster: ein Postgres-Cluster pro Projekt
Auf dieser Ebene (siehe unseren Vergleich dediziert vs. gemeinsam genutzte Basis) erhält jedes Projekt seinen eigenen CloudNativePG-Cluster und sein eigenes max_connections-Budget, dessen Größe sich an der Größe der Instanz orientiert:
| kostenlos (gewidmet) | max_connections 50 | 1 Instanz · 500 m vCPU · 512 Mi |
|---|---|---|
| Profi (Standard) | max_connections 200 | 2 Instanzen · 1 vCPU · 2Gi |
| Team | max_connections 300 | 3 Instanzen · 2 vCPU · 3Gi |
| Geschäft | max_connections 400 | 3 Instanzen · 2 vCPU · 4Gi |
Gemeinsame Cluster: mehrere Projekte einer Organisation, ein gemeinsames Budget
Auf diesem zweiten Pfad verbinden sich alle Projekte derselben Organisation über einen CNPG-Pooler (PgBouncer, transaction-Modus) vor einem gemeinsam genutzten Primärserver:
| kostenlos | max_connections 50 | max_client_conn 100 | max_user_connections 20 |
|---|---|---|---|
| Profi | max_connections 100 | max_client_conn 200 | max_user_connections 60 |
| Team | max_connections 200 | max_client_conn 400 | max_user_connections 150 |
Alle Projekte in einer Organisation sind über eine gemeinsame Anwendungsrolle miteinander verbunden. Daher begrenzt allein max_user_connections die Gesamtzahl der Serververbindungen, die diese Rolle im gesamten Cluster öffnen kann: Dies ist der eigentliche Cluster-globale Schutz, nicht max_client_conn, der nur Clientverbindungen zum Pooler selbst begrenzt.
Dieser Pooler bedient jedoch nur den SDK-Anwendungsverkehr. PostgREST bleibt seinerseits direkt mit dem primären Dienst (-rw) verbunden: Das Pooling im Transaktionsmodus würde seinen Schema-Neulademechanismus zerstören, der auf einen dedizierten LISTEN-Kanal namens pgrstlauscht. Seine eigenen Verbindungen (2 pro Replikat auf der gemeinsam genutzten Ebene, 10 pro Replikat auf der dedizierten Ebene) zählen daher direkt im max_connections-Budget des Primärservers, außerhalb jedes Poolers, genau die Art von „vergessener“ Verbindung, die Schritt 1 des folgenden Verfahrens umfassen muss.
Der Code dokumentiert diese Shared-Pooler-Budgets explizit als Startwerte, die unter realen Bedingungen durch Messung von pg_stat_activity unter Last zu kalibrieren sind, und nicht als feste Zahlen aus einem veröffentlichten Benchmark. Dies ist die gleiche Disziplin, die in unserer -Benchmark-Methodikbeschrieben wird: Erst messen, dann anpassen, nicht raten, dann hoffen. Diese Cluster laufen auf PostgreSQL 16, eine Auswahl, die in unserem Vergleich Postgres 16 vs. 17 vs. 18dokumentiert ist.
Das 5-stufige Verfahren zur Größenbestimmung von max_connections ohne Pooling
Dieses Verfahren ist nicht von einem bestimmten Tool abhängig: Es gilt für jeden verwalteten oder selbst gehosteten Postgres-Server.
- Zählen Sie Ihre tatsächlichen Clientverbindungen. Anzahl der Anwendungsprozesse multipliziert mit der Größe ihres internen Pools, plus Verwaltungstools, Replikation und Überwachung. Es ist diese Zahl, nicht die Formel, die die Untergrenze für max_connections festlegt.
- Berechnen Sie die ideale Parallelität Ihrer Hardware mit der Formel aus dem PostgreSQL-Wiki: (physische Kerne × 2) + effiziente Festplatten. Diese Zahl gibt an, wie viele dieser Verbindungen tatsächlich parallel arbeiten können, ohne dass der Durchsatz beeinträchtigt wird.
- Legen Sie „max_connections“ über dem tatsächlichen Bedarf für Schritt 1 fest, mit Spielraum für
superuser_reserved_connectionsund für alle Admin-Tools, die ihre eigenen Verbindungen außerhalb der Anwendung öffnen. - Übernehmen Sie die Änderung mit ALTER SYSTEM SET und starten Sie dann den Server neu. Dies ist ein Postmaster-Parameter: Ein einfaches Neuladen reicht nicht aus, wie oben beschrieben.
- Überwachen Sie pg_stat_activity im Laufe der Zeit. Wenn die Anzahl der inaktiven Verbindungen die Anzahl der aktiven Verbindungen bei weitem übersteigt, handelt es sich nicht um ein max_connections-Problem: Es ist das Signal, dass Sie einen Pooler vor dem Server benötigen, nicht eine höhere Zahl.
Die Überwachungsanfrage aus Schritt 5, direkt nutzbar:
Wenn die Formel nicht mehr reicht: Die Anzeichen dafür, dass Sie einen Pooler brauchen
Drei Signale kehren systematisch zurück, wenn max_connections allein nicht mehr ausreicht, unabhängig von ihrem Wert.
- Der Fehler
FATAL: sorry, too many clients alreadytritt während der Spitzenlast auf, während sich die meisten vonpg_stat_activityangezeigten Verbindungen im Ruhezustand befinden. - Die Anwendung läuft in einer serverlosen Umgebung oder mit kurzlebigen Workern (Edge-Funktionen, kurze Jobs), die Verbindungen viel schneller öffnen und schließen, als das Prozess-pro-Verbindung-Modell von Postgres dafür ausgelegt ist.
- Die obige Formel und das obige Verfahren wurden bereits angewendet, und der tatsächliche Bedarf an Clientverbindungen übersteigt weiterhin den verfügbaren Speicher, der zugewiesen werden kann, ohne work_mem oder shared_buffers zu gefährden.
In diesen drei Fällen ist die richtige Antwort fast immer ein Pooler zwischen der Anwendung und Postgres und kein höherer max_connections. Unser -Vergleich PgBouncer, Supavisor und PgCat beschreibt die drei Optionen im Detail, und unser -Leitfaden zum Transaktionsmodus erklärt den häufigsten Kompromiss, sobald der Pooler vorhanden ist. Informationen zu allen Postgres-Tunings, die über Verbindungen hinausgehen, finden Sie in unserer Produktions-Postgres-Tuning-Checkliste.