01Sports and chess retailer · OpenCart 3 · 24 579 products
One request in seven was failing. The cause was a table nobody had opened.
Symptom
Roughly 15% of requests returned HTTP 500 — 825 of them in a ninety-minute sample. The daily count was doubling: 17 fatal errors on 4 August, 413 on the 18th, 915 on the 21st. The hosting company pointed at the connection limit and stopped there.
Measured
Every fatal error was the same line: the database connection inside the session handler. The host confirmed the account was hitting its cap of 30 concurrent connections.
The session table held 18 715 802 rows and 2 284 MB — 89% of the entire database. Sessions from 2023 were still in it.
Every request, including every bot, writes to that table. Against 2.3 GB each write holds its connection long enough for thirty of them to overlap. The server itself was healthy: 40 cores at 40% load, 67 GB RAM free. The neighbours were not the problem.
Cause
OpenCart 3 compares an integer against a datetime column in its session garbage collector, so the cleanup query matched nothing — not once, in three years. Sessions simply accumulated until the connection cap did the rest.
Result
22 839 142 rows deleted in 17 minutes, in batches of 5 000 with a pause between them, while the shop stayed open. The server load average went down during the cleanup, not up.