MySQL

How to Fix "Out of Memory (Needed X Bytes)" Error in MySQL

4 min read by DebuggedIt

Quick answer

MySQL refuses to run a query or crashes outright, reporting it needed a specific number of bytes it couldn't allocate. This means MySQL's memory usage,...

MySQL refuses to run a query or crashes outright, reporting it needed a specific number of bytes it couldn't allocate. This means MySQL's memory usage, combined with everything else running on the same machine, exceeded what the OS could actually provide β€” usually a sign of misconfigured buffer sizes relative to available RAM, not a MySQL bug.

The Problem

A query fails with a specific memory allocation error:

ERROR 5 (HY000): Out of memory (Needed 4194304 bytes)

Or MySQL itself gets killed by the Linux OOM killer, which shows up in the system log rather than a MySQL error at all:

$ dmesg | grep -i oom
Out of memory: Killed process 2841 (mysqld) total-vm:4823012kB, anon-rss:3921456kB

Either way, the underlying issue is the same: MySQL, along with everything else on the box, asked for more memory than the system had available.

Why It Happens

MySQL's memory usage comes from several distinct pools, and the most common misconfiguration is setting per-connection buffers too high relative to max_connections, since those buffers get multiplied by every simultaneous connection. Common causes:

  • innodb_buffer_pool_size set too large for the machine's actual RAM, leaving too little headroom for everything else the OS needs to run.
  • Per-connection buffers multiplied across many connections β€” settings like sort_buffer_size, join_buffer_size, and read_buffer_size are allocated per-connection (sometimes per-operation within a connection), so a generous-looking setting can add up to gigabytes under real concurrent load.
  • A single query genuinely needs more memory than is available β€” a huge sort, a large temporary table, or an unindexed join over millions of rows.
  • Other processes on the same machine (application servers, caches, background jobs) are competing for the same limited RAM, leaving MySQL with less than its configuration assumes.
  • Swap is disabled or too small, removing the safety margin the OS would otherwise use before triggering an OOM kill.

The Fix

Check total system memory and how much MySQL is currently configured to use:

free -h
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';

A common rule of thumb on a dedicated database server is setting innodb_buffer_pool_size to roughly 60-70% of total RAM, leaving room for the OS, per-connection buffers, and other processes:

[mysqld]
innodb_buffer_pool_size = 4G   # on an 8GB machine, for example

Check and reduce per-connection buffer settings if they're set unusually high β€” these get multiplied by concurrent connections, so a value that seems reasonable for one connection can be dangerous at scale:

SHOW VARIABLES LIKE 'sort_buffer_size';
SHOW VARIABLES LIKE 'join_buffer_size';
SHOW VARIABLES LIKE 'read_buffer_size';
[mysqld]
sort_buffer_size = 2M
join_buffer_size = 2M
read_buffer_size = 1M

Calculate the theoretical worst case to sanity-check your settings against max_connections:

# Rough worst-case per-connection memory usage
# (sort_buffer + join_buffer + read_buffer + ...) Γ— max_connections
# should stay comfortably under available RAM minus the buffer pool

Restart MySQL after changing configuration, and monitor actual usage afterward:

sudo systemctl restart mysql
SHOW STATUS LIKE 'Threads_connected';

Still Not Working?

If the buffer pool and per-connection settings look reasonable but a specific query still triggers the error, that individual query may genuinely need more memory than it should β€” usually because it's missing an index and forcing a large in-memory sort or temporary table. Check the query's execution plan:

EXPLAIN SELECT * FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.created_at > '2026-01-01'
ORDER BY o.total DESC;

A plan showing Using filesort or Using temporary on a large table is a strong signal that adding the right index would reduce memory pressure dramatically, often more effectively than any server-level memory tuning:

CREATE INDEX idx_orders_created_total ON orders (created_at, total);

If the machine is shared with other services and memory pressure comes from outside MySQL entirely, consider whether MySQL genuinely needs a dedicated host or container with guaranteed memory limits, rather than continuing to tune MySQL's own settings against a moving target of available system memory.