{"id":941,"date":"2026-08-21T23:27:41","date_gmt":"2026-08-21T23:27:41","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=941"},"modified":"2026-08-21T23:27:41","modified_gmt":"2026-08-21T23:27:41","slug":"pgbouncer-connection-pooling-postgresql-vps","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/","title":{"rendered":"PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing"},"content":{"rendered":"<p class=\"wp-block-paragraph\">PostgreSQL is memory-hungry per connection: each idle client connection can consume several megabytes of RAM, and on a small VPS with 2\u20134 GB of RAM, an application that opens hundreds of connections can exhaust memory before the database even does any real work. PgBouncer fixes that by sitting between your application and PostgreSQL and multiplexing many client connections onto a small pool of server connections. This guide covers installation, configuration, pool sizing, and the pitfalls to avoid.<\/p>\n\n<h2 class=\"wp-block-heading\">Do you actually need a pooler?<\/h2>\n\n<p class=\"wp-block-paragraph\">You need PgBouncer if your application opens many short-lived connections \u2014 typical for server-side frameworks, web apps with per-request connections, or ORMs that do not reuse connections well. You may not need it if your app uses a single long-lived connection pool that is already sized to your RAM. A quick check: count connections with <code>SELECT count(*) FROM pg_stat_activity;<\/code> and compare against your VPS memory.<\/p>\n\n<h2 class=\"wp-block-heading\">Installing PgBouncer<\/h2>\n\n<p class=\"wp-block-paragraph\">PgBouncer is in the standard repositories of every major distribution:<\/p>\n\n<ul class=\"wp-block-list\"><li>Debian\/Ubuntu: <code>apt install pgbouncer<\/code><\/li><li>RHEL\/AlmaLinux: <code>dnf install pgbouncer<\/code><\/li><\/ul>\n\n<p class=\"wp-block-paragraph\">Configuration lives in <code>\/etc\/pgbouncer\/pgbouncer.ini<\/code>, with authentication in <code>\/etc\/pgbouncer\/userlist.txt<\/code>.<\/p>\n\n<h2 class=\"wp-block-heading\">Configuring pgbouncer.ini<\/h2>\n\n<p class=\"wp-block-paragraph\">A minimal working configuration looks like this:<\/p>\n\n<p class=\"wp-block-paragraph\"><code>[databases]<br>mydb = host=\/var\/run\/postgresql port=5432 dbname=mydb<br><br>[pgbouncer]<br>listen_addr = 127.0.0.1<br>listen_port = 6432<br>auth_type = md5<br>auth_file = \/etc\/pgbouncer\/userlist.txt<br>pool_mode = transaction<br>max_client_conn = 1000<br>default_pool_size = 20<\/code><\/p>\n\n<ul class=\"wp-block-list\"><li><code>listen_addr = 127.0.0.1<\/code> \u2014 bind to localhost so clients reach PgBouncer through the same host; never expose 6432 publicly<\/li><li><code>pool_mode = transaction<\/code> \u2014 the right default for web workloads; connections are recycled after each transaction<\/li><li><code>max_client_conn<\/code> \u2014 the maximum number of client connections PgBouncer will accept<\/li><li><code>default_pool_size<\/code> \u2014 server connections kept open per database, sized to your CPU and RAM<\/li><\/ul>\n\n<h2 class=\"wp-block-heading\">Setting up the auth file<\/h2>\n\n<p class=\"wp-block-paragraph\">Create <code>userlist.txt<\/code> with the database users PgBouncer may authenticate. Passwords must be MD5 hashes in the format PostgreSQL uses:<\/p>\n\n<p class=\"wp-block-paragraph\"><code>\"myapp\" \"md5\" + md5(password + username)<\/code><\/p>\n\n<p class=\"wp-block-paragraph\">You can generate the hash with <code>SELECT md5('password' || 'myapp');<\/code> in psql, or copy the value of <code>rolpassword<\/code> from <code>pg_authid<\/code> if you have access. Then restart PgBouncer: <code>systemctl restart pgbouncer<\/code>.<\/p>\n\n<h2 class=\"wp-block-heading\">Pool modes: transaction vs session<\/h2>\n\n<p class=\"wp-block-paragraph\">The <code>pool_mode<\/code> setting changes how aggressively connections are recycled. <code>transaction<\/code> mode returns a server connection to the pool as soon as the current transaction finishes, which means 100 concurrent clients can share as few as 10\u201320 server connections. <code>session<\/code> mode keeps the association for the entire client session \u2014 closer to what a single long-lived connection looks like, but it needs more server connections.<\/p>\n\n<p class=\"wp-block-paragraph\">Use <code>transaction<\/code> mode for web applications and APIs: it gives the biggest memory savings. Use <code>session<\/code> mode only for clients that rely on session-scoped state such as <code>SET<\/code> statements, temporary tables, or advisory locks held across transactions.<\/p>\n\n<h2 class=\"wp-block-heading\">Securing the connection<\/h2>\n\n<p class=\"wp-block-paragraph\">PgBouncer should never be exposed to the public internet. Bind it to <code>127.0.0.1<\/code> and let your application connect over localhost, or put it behind a firewall if your application runs on another host. For remote clients, add TLS on top:<\/p>\n\n<ul class=\"wp-block-list\"><li><code>client_tls_sslmode = require<\/code> \u2014 encrypt client-to-PgBouncer traffic<\/li><li><code>server_tls_sslmode = require<\/code> \u2014 encrypt PgBouncer-to-PostgreSQL traffic<\/li><li>Point <code>client_tls_cert_file<\/code> and <code>client_tls_key_file<\/code> at a certificate for your hostname<\/li><\/ul>\n\n<p class=\"wp-block-paragraph\">Keep <code>auth_type<\/code> at <code>md5<\/code> or <code>scram-sha-256<\/code> rather than <code>trust<\/code>, even on localhost \u2014 a misconfigured application should not get in without credentials.<\/p>\n\n<h2 class=\"wp-block-heading\">Sizing the pools for your VPS<\/h2>\n\n<p class=\"wp-block-paragraph\">The two numbers that matter are <code>default_pool_size<\/code> and <code>max_client_conn<\/code>. A good starting point on a 2 vCPU \/ 4 GB VPS:<\/p>\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Setting<\/th><th>Value<\/th><th>Rationale<\/th><\/tr><\/thead><tbody><tr><td>default_pool_size<\/td><td>10\u201320<\/td><td>Each server connection costs RAM; 20 connections is plenty for most web apps on 4 GB<\/td><\/tr><tr><td>max_client_conn<\/td><td>500\u20131000<\/td><td>Clients are cheap (they only queue); cap them to avoid runaway apps<\/td><\/tr><tr><td>reserve_pool_size<\/td><td>5<\/td><td>Kept free for admin queries so the app cannot starve you out<\/td><\/tr><tr><td>server_idle_timeout<\/td><td>300<\/td><td>Close idle server connections to free memory<\/td><\/tr><\/tbody><\/table><\/figure>\n\n<p class=\"wp-block-paragraph\">Monitor with <code>SHOW POOLS;<\/code> and <code>SHOW STATS;<\/code> from <code>psql -p 6432 pgbouncer<\/code>. If <code>maxwait<\/code> climbs, your pool is too small; if server connections sit idle, shrink it.<\/p>\n\n<h2 class=\"wp-block-heading\">Pointing your application at PgBouncer<\/h2>\n\n<p class=\"wp-block-paragraph\">Change the application&#8217;s database host and port to <code>127.0.0.1:6432<\/code> and keep the same database name and credentials. Keep one direct connection to PostgreSQL on port 5432 for administrative work such as migrations, and be careful with features PgBouncer does not handle well:<\/p>\n\n<ul class=\"wp-block-list\"><li>Prepared statements in transaction mode can break; enable <code>server_prepare_mode<\/code> or use the session pool for those clients<\/li><li>Features like <code>LISTEN\/NOTIFY<\/code> and advisory locks behave differently across pooled connections<\/li><li>Long-running reporting queries will hold a server connection; route them through a separate pool or database entry<\/li><\/ul>\n\n<h2 class=\"wp-block-heading\">Monitoring and common mistakes<\/h2>\n\n<ul class=\"wp-block-list\"><li>Watch memory: if PostgreSQL still uses too much RAM, reduce <code>shared_buffers<\/code> and <code>work_mem<\/code> before growing the pool<\/li><li>Set <code>statement_timeout<\/code> in PostgreSQL so one slow query cannot hog a pooled connection<\/li><li>Do not expose port 6432 publicly; PgBouncer is not a security boundary<\/li><li>Test failover: if PostgreSQL restarts, PgBouncer should reconnect automatically<\/li><\/ul>\n\n<p class=\"wp-block-paragraph\">PgBouncer removes one of the most common memory ceilings on small database servers. If you are still deciding where to host that database, see the full VPS comparison on our table to compare plans with enough RAM headroom, and browse our provider breakdowns and buying guides on the main site for PostgreSQL tuning guides that complement this setup.<\/p>\n\n<p class=\"wp-block-paragraph\">Looking for a place to run these setups? <a href=\"https:\/\/interserver.net\/vps?id=1067805&amp;sid=virtualserversvps\" rel=\"noreferrer noopener sponsored\" target=\"_blank\">InterServer VPS plans<\/a> offer straightforward pricing with plenty of headroom, and <a href=\"https:\/\/cloudways.com\/en\/?id=2010927&amp;data1=virtualserversvps\" rel=\"noreferrer noopener sponsored\" target=\"_blank\">Cloudways managed cloud hosting<\/a> is a solid choice if you prefer a managed platform on top of fast infrastructure. (Disclosure: we may earn a commission if you sign up through these links, at no extra cost to you.)<\/p>","protected":false},"excerpt":{"rendered":"<p>PostgreSQL is memory-hungry per connection: each idle client connection can consume several megabytes of RAM, and on a small VPS with 2\u20134 GB of RAM, an application that opens hundreds&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-941","post","type-post","status-publish","format-standard","hentry","category-performance-optimization"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing - Virtual Servers VPS Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing\" \/>\n<meta property=\"og:description\" content=\"PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-21T23:27:41+00:00\" \/>\n<meta name=\"author\" content=\"Virtual-Servers-Vps-Editor\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Virtual-Servers-Vps-Editor\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/\",\"name\":\"PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-08-21T23:27:41+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/\",\"name\":\"Virtual Servers VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\",\"name\":\"Virtual-Servers-Vps-Editor\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"caption\":\"Virtual-Servers-Vps-Editor\"},\"sameAs\":[\"https:\/\/virtualserversvps.com\/blog\"],\"url\":\"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing - Virtual Servers VPS Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/","og_locale":"en_US","og_type":"article","og_title":"PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing","og_description":"PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing","og_url":"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-08-21T23:27:41+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/","url":"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/","name":"PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-08-21T23:27:41+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/pgbouncer-connection-pooling-postgresql-vps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"PgBouncer on a VPS: PostgreSQL Connection Pooling Setup and Sizing"}]},{"@type":"WebSite","@id":"https:\/\/virtualserversvps.com\/blog\/#website","url":"https:\/\/virtualserversvps.com\/blog\/","name":"Virtual Servers VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0","name":"Virtual-Servers-Vps-Editor","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","caption":"Virtual-Servers-Vps-Editor"},"sameAs":["https:\/\/virtualserversvps.com\/blog"],"url":"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/"}]}},"_links":{"self":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/941","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/comments?post=941"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/941\/revisions"}],"predecessor-version":[{"id":943,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/941\/revisions\/943"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=941"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=941"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=941"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}