{"id":1537,"date":"2026-10-22T22:37:21","date_gmt":"2026-10-22T22:37:21","guid":{"rendered":"https:\/\/affordablevpsserver.com\/blog\/?p=1537"},"modified":"2026-10-22T22:37:21","modified_gmt":"2026-10-22T22:37:21","slug":"php-fpm-pm-max-children-sizing-low-ram-vps","status":"publish","type":"post","link":"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/","title":{"rendered":"PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">On a 1 GB VPS running nginx and PHP-FPM, the single most consequential number in the entire configuration is <code>pm.max_children<\/code>. Set it too low and requests queue behind a busy worker while the CPU sits idle. Set it too high and the OOM killer resolves the ambiguity for you, usually at the worst possible moment. This is how to calculate it, what to change alongside it, and how to verify the result under real load.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Measure the Worker Before You Size the Pool<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The calculation needs one measured input: how much memory a single PHP-FPM worker actually holds under your application. Guessing this is how people end up with 25 children on a 1 GB host.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Start the pool with a small number of children and put real traffic through it, or replay a few hundred requests with <code>ab<\/code> or <code>wrk<\/code>.<\/li><li>Read resident memory per worker: <code>ps -o pid,rss,cmd -C php-fpm8.3<\/code> &mdash; RSS is in kilobytes.<\/li><li>Take the largest value across workers, not the average. The peak worker is the one that decides whether you OOM.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Typical values in 2026, for a WordPress install with a page cache enabled and 15&ndash;25 plugins:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Stack<\/th><th>Per-worker RSS<\/th><th>Notes<\/th><\/tr><\/thead><tbody><tr><td>Bare PHP script \/ small API<\/td><td>25&ndash;40 MB<\/td><td>No framework, opcache on<\/td><\/tr><tr><td>Laravel or Symfony, small app<\/td><td>45&ndash;70 MB<\/td><td>Depends heavily on autoload size<\/td><\/tr><tr><td>WordPress, lean plugin set<\/td><td>50&ndash;70 MB<\/td><td>Object cache off<\/td><\/tr><tr><td>WordPress + WooCommerce<\/td><td>80&ndash;140 MB<\/td><td>Peak pages during checkout are higher<\/td><\/tr><tr><td>WordPress + heavy page builder<\/td><td>120&ndash;200 MB<\/td><td>Elementor-class builders inflate every request<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">The pm.max_children Formula<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The standard calculation is memory available to PHP divided by per-worker RSS:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Step 1.<\/strong> Take total RAM and subtract a fixed overhead: 250 MB on a 1 GB box, 350 MB on 2 GB. That covers the kernel, sshd, systemd, nginx and the Docker daemon if present.<\/li><li><strong>Step 2.<\/strong> Subtract the database. A tuned MariaDB with a 128 MB buffer pool uses roughly 300 MB total; with 256 MB, roughly 450 MB.<\/li><li><strong>Step 3.<\/strong> The remainder is PHP&#8217;s budget. Keep 10% of it free as emergency headroom.<\/li><li><strong>Step 4.<\/strong> Divide by the measured peak worker RSS and round <em>down<\/em>.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">On a 1 GB VPS with MariaDB: 1024 &minus; 250 &minus; 300 = 474 MB, minus 10% headroom = 427 MB. At 60 MB per worker that is 7 children. At 110 MB per worker (WooCommerce) that is 3. The difference between those two answers is not a preference; it is arithmetic, and it is the reason generic &#8220;set it to 10&#8221; advice breaks sites.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why Not Simply Use pm = dynamic With High Max<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Many guides recommend <code>pm = dynamic<\/code> with <code>pm.max_children<\/code> set to 25 and let the process manager sort it out. On a 1 GB host this is a slow-motion OOM. The process manager will happily spawn children up to the maximum when requests queue, and the kernel will kill whichever process it finds largest. On small machines, the pool should be small and fixed, with the web server, not PHP, absorbing the excess.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Setting<\/th><th>1 GB VPS<\/th><th>2 GB VPS<\/th><th>4 GB VPS<\/th><\/tr><\/thead><tbody><tr><td><code>pm<\/code><\/td><td>static (or dynamic with narrow range)<\/td><td>dynamic<\/td><td>dynamic<\/td><\/tr><tr><td><code>pm.max_children<\/code><\/td><td>4&ndash;7<\/td><td>8&ndash;12<\/td><td>16&ndash;24<\/td><\/tr><tr><td><code>pm.start_servers<\/code><\/td><td>n\/a for static<\/td><td>4<\/td><td>8<\/td><\/tr><tr><td><code>pm.min_spare_servers<\/code><\/td><td>n\/a<\/td><td>3<\/td><td>6<\/td><\/tr><tr><td><code>pm.max_spare_servers<\/code><\/td><td>n\/a<\/td><td>8<\/td><td>14<\/td><\/tr><tr><td><code>pm.max_requests<\/code><\/td><td>300&ndash;500<\/td><td>500<\/td><td>500<\/td><\/tr><tr><td><code>pm.process_idle_timeout<\/code><\/td><td>10s<\/td><td>10s<\/td><td>10s<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><code>pm.max_requests<\/code> deserves a note: recycling workers after a few hundred requests limits the damage from memory leaks in plugins. It costs one request of latency per recycle. On 1 GB, where every megabyte counts, 300 is a reasonable ceiling; leaving it at 0 on a budget box means a leaky plugin eventually becomes an outage.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Each Worker Needs a vCPU to Run On<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Children beyond the number of available cores do not add throughput; they just queue inside PHP instead of in nginx. On a 1 vCPU plan, two or three workers can saturate the core, which is why a 1 vCPU VPS with 7 children runs no faster than one with 3 &mdash; it just uses more memory while doing it. The useful ratio is roughly 1.5&ndash;2 workers per vCPU for PHP-heavy work, and more only when requests spend time waiting on I\/O (external APIs, slow database queries).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is the core argument for the 2 vCPU \/ 2 GB tier over 1 vCPU \/ 1 GB for any real site: it roughly doubles both the cores available to run workers and the memory available to hold them. The price difference is usually $2&ndash;$4 a month, which is less than an hour of the time it takes to chase down an OOM incident.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Nginx Settings That Protect the Pool<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A small PHP pool needs the web server in front of it to fail politely. Three directives do most of the work:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>worker_connections 1024;<\/code> &mdash; plenty for a budget box; the real limit will be PHP, not nginx.<\/li><li><code>keepalive_timeout 15;<\/code> &mdash; shorter than default reduces the number of idle connections held against a small pool.<\/li><li>Upstream with <code>max_fails=2 fail_timeout=30s<\/code> so a struggling backend is temporarily bypassed rather than piled onto.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Then set a page cache so most requests never reach PHP at all. For WordPress, a static page cache in nginx &mdash; or a plugin that writes full-page HTML &mdash; typically serves 80&ndash;95% of requests without touching a worker. That changes the sizing calculation more than any PHP tunable: with a 90% cache hit rate, the pool only needs to absorb the remaining 10%, and peak concurrency at 50,000 monthly views drops to a handful of simultaneous requests.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Verify Under Load, Not on an Idle Box<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Configuration that looks correct on an idle server frequently falls over under concurrency. Test it:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Run <code>wrk -t2 -c10 -d60s --latency https:\/\/example.com\/<\/code> against an uncached endpoint.<\/li><li>In parallel, watch <code>vmstat 2<\/code>. Swap in\/out should stay at zero; <code>r<\/code> (run queue) above your vCPU count means CPU-bound.<\/li><li>Watch <code>ps -o rss,cmd -C php-fpm8.3 | sort -n | tail -3<\/code> &mdash; confirm workers stayed within the sized footprint.<\/li><li>Check the FPM status page (<code>pm.status_path = \/status<\/code>) for <em>listen queue<\/em> and <em>max children reached<\/em>. A non-zero listen queue with spare RAM means max_children is too low; a max-children-reached count while swap grows means it is too high.<\/li><li>Repeat after enabling the cache. Requests per second should rise sharply and CPU should fall.<\/li><\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">If throughput plateaus while a listen queue forms and RAM is unused, add one or two children. If swap grows before throughput plateaus, remove them. The status page tells you which case you are in within a minute, and the numbers are far more reliable than a default config copied from a tutorial. Our <a href=\"https:\/\/affordablevpsserver.com\/blog\/how-much-ram-small-business-website-actually-need\/\">RAM sizing figures by CMS and traffic level<\/a> give you a second opinion on whether the plan itself is the problem, and the <a href=\"https:\/\/affordablevpsserver.com\/#providers\">budget VPS comparison table<\/a> shows what the next tier up costs when it is.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>On a 1 GB VPS running nginx and PHP-FPM, the single most consequential number in the entire configuration is pm.max_children. Set it too low and requests queue behind a busy worker while the CPU sits idle. Set it too high and the OOM killer resolves the ambiguity for you, usually at the worst possible moment. [&hellip;]<\/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":[2],"tags":[],"class_list":["post-1537","post","type-post","status-publish","format-standard","hentry","category-budget-vps-guides"],"blocksy_meta":[],"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>PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load - Affordable VPS Server Blog<\/title>\n<meta name=\"description\" content=\"On a 1 GB VPS running nginx and PHP-FPM, the single most consequential number in the entire configuration is pm.max_children. Set it too low and requests\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load\" \/>\n<meta property=\"og:description\" content=\"PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load\" \/>\n<meta property=\"og:url\" content=\"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/\" \/>\n<meta property=\"og:site_name\" content=\"Affordable VPS Server Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-22T22:37:21+00:00\" \/>\n<meta name=\"author\" content=\"Affordable-Vps-Server-Author\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Affordable-Vps-Server-Author\" \/>\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:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/\",\"url\":\"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/\",\"name\":\"PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load - Affordable VPS Server Blog\",\"isPartOf\":{\"@id\":\"https:\/\/affordablevpsserver.com\/blog\/#website\"},\"datePublished\":\"2026-10-22T22:37:21+00:00\",\"author\":{\"@id\":\"https:\/\/affordablevpsserver.com\/blog\/#\/schema\/person\/685a02c93a3c45030f7427ec928b0df7\"},\"description\":\"On a 1 GB VPS running nginx and PHP-FPM, the single most consequential number in the entire configuration is pm.max_children. Set it too low and requests\",\"breadcrumb\":{\"@id\":\"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/affordablevpsserver.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/affordablevpsserver.com\/blog\/#website\",\"url\":\"https:\/\/affordablevpsserver.com\/blog\/\",\"name\":\"Affordable VPS Server Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/affordablevpsserver.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/affordablevpsserver.com\/blog\/#\/schema\/person\/685a02c93a3c45030f7427ec928b0df7\",\"name\":\"Affordable-Vps-Server-Author\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/affordablevpsserver.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/8fa20973a7dd04621d396c26ba26b5c5e6c19595583335121958527393f6f95e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/8fa20973a7dd04621d396c26ba26b5c5e6c19595583335121958527393f6f95e?s=96&d=mm&r=g\",\"caption\":\"Affordable-Vps-Server-Author\"},\"sameAs\":[\"https:\/\/affordablevpsserver.com\/blog\"],\"url\":\"https:\/\/affordablevpsserver.com\/blog\/author\/affordablevpsserver\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load - Affordable VPS Server Blog","description":"On a 1 GB VPS running nginx and PHP-FPM, the single most consequential number in the entire configuration is pm.max_children. Set it too low and requests","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:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/","og_locale":"en_US","og_type":"article","og_title":"PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load","og_description":"PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load","og_url":"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/","og_site_name":"Affordable VPS Server Blog","article_published_time":"2026-10-22T22:37:21+00:00","author":"Affordable-Vps-Server-Author","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Affordable-Vps-Server-Author","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/","url":"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/","name":"PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load - Affordable VPS Server Blog","isPartOf":{"@id":"https:\/\/affordablevpsserver.com\/blog\/#website"},"datePublished":"2026-10-22T22:37:21+00:00","author":{"@id":"https:\/\/affordablevpsserver.com\/blog\/#\/schema\/person\/685a02c93a3c45030f7427ec928b0df7"},"description":"On a 1 GB VPS running nginx and PHP-FPM, the single most consequential number in the entire configuration is pm.max_children. Set it too low and requests","breadcrumb":{"@id":"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/affordablevpsserver.com\/blog\/php-fpm-pm-max-children-sizing-low-ram-vps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/affordablevpsserver.com\/blog\/"},{"@type":"ListItem","position":2,"name":"PHP-FPM pm.max_children on a 1 GB VPS: How to Calculate It and Verify It Under Load"}]},{"@type":"WebSite","@id":"https:\/\/affordablevpsserver.com\/blog\/#website","url":"https:\/\/affordablevpsserver.com\/blog\/","name":"Affordable VPS Server Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/affordablevpsserver.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/affordablevpsserver.com\/blog\/#\/schema\/person\/685a02c93a3c45030f7427ec928b0df7","name":"Affordable-Vps-Server-Author","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/affordablevpsserver.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/8fa20973a7dd04621d396c26ba26b5c5e6c19595583335121958527393f6f95e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/8fa20973a7dd04621d396c26ba26b5c5e6c19595583335121958527393f6f95e?s=96&d=mm&r=g","caption":"Affordable-Vps-Server-Author"},"sameAs":["https:\/\/affordablevpsserver.com\/blog"],"url":"https:\/\/affordablevpsserver.com\/blog\/author\/affordablevpsserver\/"}]}},"_links":{"self":[{"href":"https:\/\/affordablevpsserver.com\/blog\/wp-json\/wp\/v2\/posts\/1537","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/affordablevpsserver.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/affordablevpsserver.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/affordablevpsserver.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/affordablevpsserver.com\/blog\/wp-json\/wp\/v2\/comments?post=1537"}],"version-history":[{"count":1,"href":"https:\/\/affordablevpsserver.com\/blog\/wp-json\/wp\/v2\/posts\/1537\/revisions"}],"predecessor-version":[{"id":1538,"href":"https:\/\/affordablevpsserver.com\/blog\/wp-json\/wp\/v2\/posts\/1537\/revisions\/1538"}],"wp:attachment":[{"href":"https:\/\/affordablevpsserver.com\/blog\/wp-json\/wp\/v2\/media?parent=1537"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/affordablevpsserver.com\/blog\/wp-json\/wp\/v2\/categories?post=1537"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/affordablevpsserver.com\/blog\/wp-json\/wp\/v2\/tags?post=1537"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}