How Much RAM WordPress Needs: 262 MB. The Machine Needs 753 MB.

How much RAM does WordPress actually need?

On our live site the whole stack — Caddy, php-fpm and MariaDB — uses 262 MiB, and the machine as a whole uses 753 MiB. The difference is Ubuntu and the Docker runtime, which cost 491 MiB — 1.9× the application. dockerd and containerd alone are 105 MB.

Key finding Summing per-process RSS overstates php-fpm by about 2×. Our three workers plus master read 191.4 MB in ps aux, but the container’s cgroup total is 97.34 MiB, because RSS counts every shared page once per worker. Any pm.max_children formula fed an RSS number inherits that error.

Our php-fpm container runs three workers and a master. ps aux reports them at 59.0, 58.7, 57.3 and 17.4 MB — 191.4 MB in total. The container’s actual memory usage is 97.34 MiB.

Both numbers are correct. The first one double-counts.

KEY FINDING: summing per-process RSS overstates php-fpm memory by roughly 2×, because RSS counts every shared page once per worker. If you sized a server by multiplying a per-worker figure by your worker count, you provisioned about twice the RAM that component needed.

Two more numbers from the same machine: the whole WordPress stack — web server, PHP and database — uses 262 MiB, and the operating system plus container runtime under it uses 491 MiB. The machinery costs 1.9× the application.

Measured 30 August 2026, 27 hours after container start.

What the existing guides answer, and where they stop

We read the first page of results for how much RAM does WordPress need. Most of it is recommendation writing from companies that sell hosting. SSD Nodes is representative: 512 MB to 1 GB per site, while stating plainly that “WordPress RAM requirements aren’t officially published.”

One is not like the others. HelpWithWeb publishes real measurements and says how it got them — ps aux RSS readings on live PHP 8.1–8.3 sites with 15 to 40 plugins, under real traffic:

Site type Per php-fpm worker
Plain blog, light plugins 40–70 MB
Business site with a page builder 80–130 MB
WooCommerce / membership 100–200 MB

That is a good measurement of a worker, taken under load across many sites, and this page does not improve on it. Our own ps readings land in the same range: 57–59 MB per worker for a plain blog.

The problem is what happens next. A per-worker figure is only useful if you multiply it by your worker count — and that multiplication is where sizing goes wrong, for a reason that has nothing to do with the measurement being wrong.

What is running

Component Image
Web server / TLS caddy:2-alpine
WordPress wordpress:6-php8.3-fpm-alpine
Database mariadb:11

Host: Amazon Lightsail, $12/month — 2 GB RAM, 2 vCPU, 60 GB SSD, 3 TB transfer (official pricing). Ubuntu, Docker Compose, eleven published articles, near-zero traffic.

That last part matters, and we come back to it.

Measured memory, per container

docker stats --no-stream, cgroup memory:

Container Using Cap set % of cap
Caddy 44.97 MiB 96 MiB 46.9%
WordPress (php-fpm) 97.34 MiB 320 MiB 30.4%
MariaDB 119.6 MiB 384 MiB 31.1%
Total 261.9 MiB 800 MiB 32.7%

Memory caps are set on each container. Every one is well under its cap, so the caps are not suppressing these numbers. The database is the largest single consumer, and it is the one that grows.

Where the 2× comes from

ps aux on the same machine, php-fpm processes only:

Process RSS
worker 59.0 MB
worker 58.7 MB
worker 57.3 MB
master 17.4 MB
Sum 191.4 MB

The container is using 97.34 MiB. The sum of the parts is 1.97× the whole.

Nothing is wrong with either tool. RSS is resident set size per process, and it includes shared pages in full for every process that maps them. php-fpm workers are forked from the master: the PHP binary, every loaded extension, the opcache, and any memory the master touched before forking are one physical copy that all four processes report as theirs. ps counts that copy four times. The cgroup accounting behind docker stats counts it once — which is how much RAM you actually have to buy.

On our workers, roughly half of each worker’s RSS is shared with its siblings.

What this does to your pm.max_children

Every php-fpm tuning guide gives the same formula:

pm.max_children = available RAM / average process size

The formula is fine. The input is usually an RSS reading, and RSS is inflated. That error propagates in both directions depending on which side you solve for:

  • Sizing a server for a fixed worker count. Ten workers at a 60 MB RSS reading looks like 600 MB. If half of each worker’s RSS is shared, the real figure is closer to 300 MB. You buy twice the RAM.
  • Setting max_children for a fixed server. The same inflation makes each worker look expensive, so you cap concurrency lower than the machine can actually support, and requests queue on a box with free memory.

The fix is to measure the process group rather than a process. Three ways, all of which count shared pages once:

# containers
docker stats --no-stream

# systemd services, no containers
systemd-cgtop
cat /sys/fs/cgroup/<slice>/memory.current

# per-process, shared pages split proportionally
smem -k -P php-fpm      # read the PSS column, not RSS

PSS — proportional set size — divides each shared page by the number of processes mapping it. Summing PSS across a process group gives a total you can trust; summing RSS does not.

We did not measure the marginal cost of one additional worker, which is what you would want to plug into the formula. That needs readings at two different worker counts, and we have one. Treat “roughly half is shared” as an observation about our box, not a constant.

The whole machine

free -m, same moment:

  MiB
Total 1,906
Used 753
Buffers / cache 1,109
Available 1,152

Used is 753 MiB. The containers account for 262 MiB of it. The other 491 MiB is Ubuntu and the container runtime. The named processes, by RSS:

Process RSS
dockerd 67.2 MB
systemd-journald 48.8 MB
containerd 38.2 MB
fwupd 26.6 MB
multipathd 26.0 MB
snapd 20.0 MB
networkd-dispatcher 18.1 MB
unattended-upgrade 14.0 MB

(These are RSS figures and carry the same inflation described above, so treat each as an upper bound.)

Docker’s own daemons — dockerd plus containerd — cost 105 MB. That is 40% of what the entire WordPress stack costs. You are paying it for isolation and reproducibility, which may well be worth it. It is simply not free, and no sizing guide counts it.

Three more entries — fwupd, multipathd, snapd — total 72.6 MB and handle firmware updates, multipath storage and snap packages. A single-purpose web server does not obviously need any of them.

  MiB % of 2 GB
OS + container runtime 491 25.8%
WordPress stack 262 13.7%
Available 1,152 60.5%

If you are sizing a box for WordPress, you are mostly sizing it for Linux and Docker. The advice that says “get 2 GB” is not wrong about the box. It is pointed at the smaller half of the bill.

This also dissolves a contradiction people run into: the measurements are small, the hosting advice is large, and both are correct. They describe different things, and the gap between them is the operating system.

What this implies for a 1 GB plan

Lightsail’s 1 GB tier is the cheapest step down. Our measured total at idle is 753 MiB, and the OS share of that would not shrink on a smaller instance. On 1 GB, after the kernel’s own reservation, that is roughly 79% of memory used before a single visitor arrives.

That is arithmetic on our numbers, not an experiment. We have not run this stack on 1 GB and we are not going to tell you it works. HelpWithWeb’s decision table says 1 GB is fine for a small blog with proper caching — and caching is precisely what stops workers from multiplying.

Two vCPUs, doing nothing

Load average over 1, 5 and 15 minutes:

load average: 0.00, 0.02, 0.00

Per container: 0.00%, 0.01%, 0.01%. Swap is 2 GB configured and 30 MB used — 1.5%. The machine has never been under memory pressure.

For a content site this size, vCPU is the specification you are least likely to need and the one every plan raises alongside RAM. Our price-per-GB-of-RAM comparison shows how tightly providers bundle the two.

The disk line item nobody warns you about

docker system df:

Type Size Reclaimable
Images 1.75 GB 405 MB (23%)
Build cache 896.6 MB 450.4 MB
Local volumes 309.1 MB 0 B
Containers 57.34 kB 0 B

Build cache is 897 MB — half the size of every image on the machine, and nearly three times the site’s actual data.

Disk in use is 10 GB of 58 GB, so it is not urgent here. On a 40 GB plan with a few rebuilds behind you it stops being a footnote. docker builder prune reclaims 450 MB.

The site’s real data — WordPress files, the database, TLS certificates — is the 309 MB of volumes. Everything else is machinery.

WP_MEMORY_LIMIT is not your memory usage

Our config sets:

define('WP_MEMORY_LIMIT', '256M');

This gets read as “the site needs 256 MB” far more often than it should. It is a per-PHP-process ceiling — the most any single request may allocate before PHP kills it. It is not an allocation, not a reservation, and not a measurement.

The entire php-fpm container, master and workers together, is using 97 MiB. The 256 MB limit has never been approached.

Raising it does not make your site use more memory and does not require a bigger server. It changes when a runaway request fails.

Method and limits

What we measured. One site, one configuration, 30 August 2026, 27 hours after container start. docker stats --no-stream for per-container cgroup memory; ps aux --sort=-rss for per-process RSS; free -m and /proc/meminfo for the host; docker system df for disk; uptime for load. Instance specification confirmed against AWS’s published pricing page. We opened two of the nine first-page results to check their method and did not read all nine in full, so statements about what is unpublished describe our search, not a proof of absence.

The server runs nothing else. We checked, because the instance is named for an earlier project. The only Python processes are networkd-dispatcher and unattended-upgrade, both Ubuntu defaults. Nothing else competes for the 491 MiB.

Traffic. This site gets almost no traffic, and that single fact limits everything above. php-fpm allocates per concurrent request; the container grows with pm.max_children and with how many visitors arrive at once. MariaDB’s InnoDB buffer pool grows with the working set. 262 MiB is a floor for this stack, not a ceiling. For behaviour under load, the per-worker figures cited above are the better source.

Uptime. 27 hours. MariaDB’s memory rises over days as the buffer pool fills. Even the idle number is probably not final.

One configuration. Alpine images, php-fpm rather than Apache with mod_php, no object cache, no page-cache plugin, eleven articles, one theme. Any of those changes the number, and mod_php in particular is heavier.

We did not test 1 GB, and we did not measure the marginal cost of an additional worker. Both of those sections are arithmetic on 2 GB measurements.

What we can say is narrow: on this running WordPress site, summed RSS overstates php-fpm by about 2×, and the operating system costs more memory than WordPress does. If either holds on your machine too, the sizing question has been aimed at the wrong number.

Related

  • What a GB of RAM Actually Costs: Every Major VPS Provider
  • Four Things That Broke in Three Days of Self-Hosting WordPress on Docker and Caddy
  • Buffers / cache 1,109 Available 1,152

    Used is 753 MiB. The containers account for 262 MiB of it. The other 491 MiB is Ubuntu and the container runtime. The named processes, by RSS:

    Process RSS
    dockerd 67.2 MB
    systemd-journald 48.8 MB
    containerd 38.2 MB
    fwupd 26.6 MB
    multipathd 26.0 MB
    snapd 20.0 MB
    networkd-dispatcher 18.1 MB
    unattended-upgrade 14.0 MB

    (These are RSS figures and carry the same inflation described above, so treat each as an upper bound.)

    Docker’s own daemons — dockerd plus containerd — cost 105 MB. That is 40% of what the entire WordPress stack costs. You are paying it for isolation and reproducibility, which may well be worth it. It is simply not free, and no sizing guide counts it.

    Three more entries — fwupd, multipathd, snapd — total 72.6 MB and handle firmware updates, multipath storage and snap packages. A single-purpose web server does not obviously need any of them.

      MiB % of 2 GB
    OS + container runtime 491 25.8%
    WordPress stack 262 13.7%
    Available 1,152 60.5%

    If you are sizing a box for WordPress, you are mostly sizing it for Linux and Docker. The advice that says “get 2 GB” is not wrong about the box. It is pointed at the smaller half of the bill.

    This also dissolves a contradiction people run into: the measurements are small, the hosting advice is large, and both are correct. They describe different things, and the gap between them is the operating system.

    What this implies for a 1 GB plan

    Lightsail’s 1 GB tier is the cheapest step down. Our measured total at idle is 753 MiB, and the OS share of that would not shrink on a smaller instance. On 1 GB, after the kernel’s own reservation, that is roughly 79% of memory used before a single visitor arrives.

    That is arithmetic on our numbers, not an experiment. We have not run this stack on 1 GB and we are not going to tell you it works. HelpWithWeb’s decision table says 1 GB is fine for a small blog with proper caching — and caching is precisely what stops workers from multiplying.

    Two vCPUs, doing nothing

    Load average over 1, 5 and 15 minutes:

    load average: 0.00, 0.02, 0.00

    Per container: 0.00%, 0.01%, 0.01%. Swap is 2 GB configured and 30 MB used — 1.5%. The machine has never been under memory pressure.

    For a content site this size, vCPU is the specification you are least likely to need and the one every plan raises alongside RAM. Our price-per-GB-of-RAM comparison shows how tightly providers bundle the two.

    The disk line item nobody warns you about

    docker system df:

    Type Size Reclaimable
    Images 1.75 GB 405 MB (23%)
    Build cache 896.6 MB 450.4 MB
    Local volumes 309.1 MB 0 B
    Containers 57.34 kB 0 B

    Build cache is 897 MB — half the size of every image on the machine, and nearly three times the site’s actual data.

    Disk in use is 10 GB of 58 GB, so it is not urgent here. On a 40 GB plan with a few rebuilds behind you it stops being a footnote. docker builder prune reclaims 450 MB.

    The site’s real data — WordPress files, the database, TLS certificates — is the 309 MB of volumes. Everything else is machinery.

    WP_MEMORY_LIMIT is not your memory usage

    Our config sets:

    define('WP_MEMORY_LIMIT', '256M');

    This gets read as “the site needs 256 MB” far more often than it should. It is a per-PHP-process ceiling — the most any single request may allocate before PHP kills it. It is not an allocation, not a reservation, and not a measurement.

    The entire php-fpm container, master and workers together, is using 97 MiB. The 256 MB limit has never been approached.

    Raising it does not make your site use more memory and does not require a bigger server. It changes when a runaway request fails.

    Method and limits

    What we measured. One site, one configuration, 30 August 2026, 27 hours after container start. docker stats --no-stream for per-container cgroup memory; ps aux --sort=-rss for per-process RSS; free -m and /proc/meminfo for the host; docker system df for disk; uptime for load. Instance specification confirmed against AWS’s published pricing page. We opened two of the nine first-page results to check their method and did not read all nine in full, so statements about what is unpublished describe our search, not a proof of absence.

    The server runs nothing else. We checked, because the instance is named for an earlier project. The only Python processes are networkd-dispatcher and unattended-upgrade, both Ubuntu defaults. Nothing else competes for the 491 MiB.

    Traffic. This site gets almost no traffic, and that single fact limits everything above. php-fpm allocates per concurrent request; the container grows with pm.max_children and with how many visitors arrive at once. MariaDB’s InnoDB buffer pool grows with the working set. 262 MiB is a floor for this stack, not a ceiling. For behaviour under load, the per-worker figures cited above are the better source.

    Uptime. 27 hours. MariaDB’s memory rises over days as the buffer pool fills. Even the idle number is probably not final.

    One configuration. Alpine images, php-fpm rather than Apache with mod_php, no object cache, no page-cache plugin, eleven articles, one theme. Any of those changes the number, and mod_php in particular is heavier.

    We did not test 1 GB, and we did not measure the marginal cost of an additional worker. Both of those sections are arithmetic on 2 GB measurements.

    What we can say is narrow: on this running WordPress site, summed RSS overstates php-fpm by about 2×, and the operating system costs more memory than WordPress does. If either holds on your machine too, the sizing question has been aimed at the wrong number.

    Related

    Sources

    This page links to each vendor’s own pricing page. No affiliate links are used at this time.

Leave a Comment