Last month, our Odoo system was taking 8 seconds to load a simple sales order. Eight. Seconds.
Our users were furious. Our Management was asking questions. And I was staring at an AWS bill that showed our 4 vCPU, 16GB RAM RDS instance maxing out constantly.
The weird part? We weren't even that big. About 150 active users. Normal transaction volumes. Nothing crazy.
Turns out, the default RDS settings for PostgreSQL are set up like someone who's terrified of breaking things. Super conservative. Which is fine if you're running a hobby blog, but terrible if you're running actual business software like Odoo.
Here's what we changed, what actually worked, and what you should ignore.
The Memory Settings That Actually Matter
PostgreSQL has about 300 configuration parameters. Most of them don't matter for Odoo. But six of them will make or break your performance.
Shared Buffers
This is your database's working memory. Think of it like RAM for your most frequently accessed data.
The default on RDS is laughably small, usually around 128MB. We bumped ours to 4GB, which is about 25% of our total RAM.
Why 25%? Because PostgreSQL also relies on your operating system's file cache. If you set shared buffers too high, you're actually stealing memory from the OS cache, which hurts more than it helps.
After we made this change, our most common queries got about 40% faster. Just from this one setting.
Effective Cache Size
This one's confusing because it doesn't actually allocate memory. It just tells PostgreSQL's query planner how much memory is realistically available for caching.
We set ours to 12GB, which is roughly 75% of total RAM. This helps PostgreSQL make smarter decisions about whether to use an index or do a sequential scan.
The performance gain here isn't dramatic on individual queries, but across thousands of queries per day, it adds up.
Work Memory
This is memory allocated per operation. Sorting, hashing, that kind of thing.
Default is usually 4MB, which forces PostgreSQL to write temporary data to disk constantly. We increased ours to 32MB.
Be careful here though. If you set this too high and have 100 connections all running complex queries simultaneously, you could run out of RAM fast. That's why we also capped max connections at 100.
Maintenance Work Memory
This one's just for maintenance tasks like vacuuming and creating indexes.
We set it to 1GB. Honestly, this doesn't affect day-to-day performance much, but it makes routine maintenance way faster. Our weekly vacuum went from 45 minutes to about 12.
Checkpoint Completion Target
Checkpoints are when PostgreSQL writes all dirty data from memory to disk. If this happens too fast, you get massive I/O spikes that make everything else grind to a halt.
We set ours to 0.9, which spreads the writes out over 90% of the checkpoint interval. Smooths out the I/O load significantly.
Max Connections
We lowered this from the default 200 to 100.
Sounds backwards, right? But here's the thing. Every connection uses memory. If you allow 200 connections with 32MB work memory each, you could theoretically use 6.4GB just for query operations. That doesn't leave much for your shared buffers.
Plus, Odoo doesn't actually need 200 connections. With proper worker configuration, 100 is plenty.
Configuring Odoo To Not Waste Database Connections
Your RDS instance is only half the equation. Your Odoo application server matters just as much.
Worker Count
The formula everyone uses is CPU cores times 2, plus 1. For our 4 core instance, that's 9 workers.
We tried going higher. Didn't help. Just created more contention and used more memory.
We also tried going lower to save resources. That made response times worse because requests were queuing up waiting for available workers.
Nine turned out to be the sweet spot.
Memory Limits
Each Odoo worker can be a memory hog if you let it. We set soft limit at 2GB and hard limit at 2.5GB.
When a worker hits the soft limit, it finishes its current request then restarts. When it hits the hard limit, it dies immediately.
This prevents runaway processes from eating all your RAM.
Database Max Connections Per Worker
This one's subtle but important. By default, Odoo workers can open way more database connections than they actually need.
We capped it at 32 total across all workers. This prevents connection exhaustion on the RDS side.
The Maintenance Stuff You Can't Skip
All the configuration in the world won't help if your database is full of bloat and missing indexes.
Finding Your Slow Queries
AWS Performance Insights is actually pretty good for this. It shows you which queries are eating the most time.
We found three queries that were taking 80% of our total database time. Two were missing indexes on custom fields. One was a badly written custom report that was doing a full table scan on a 2 million row table.
Fixed those three things and saw overall response time drop by half.
Vacuuming
PostgreSQL doesn't actually delete data when you delete a row. It just marks it as deleted. Over time, this creates bloat.
Autovacuum is supposed to handle this automatically, but the default settings are too relaxed for Odoo.
The mail_message table in Odoo is especially brutal. It churns constantly. We lowered the autovacuum threshold for that specific table and it helped a lot.
Indexes
Every WHERE clause, every JOIN, every ORDER BY should ideally use an index.
We ran pg_stat_statements for a week to see which columns were being searched most often, then added indexes where they were missing.
Be careful not to go overboard though. Every index slows down writes slightly. You want indexes on frequently read columns, not everything.
Storage Type
This one's non negotiable. You need SSD storage for Odoo.
We're using GP3 with 3000 IOPS baseline. For busier systems, provisioned IOPS with io2 volumes makes sense.
Regular magnetic storage will kill your performance no matter how well you tune everything else.
The Advanced Stuff That Made A Real Difference
Once you've got the basics sorted, there are a couple more things worth doing.
Connection Pooling With PgBouncer
Opening and closing database connections is expensive. Each connection takes time and uses memory.
PgBouncer sits between Odoo and PostgreSQL and maintains a pool of persistent connections. Odoo thinks it's opening a new connection each time, but it's actually reusing existing ones.
We saw about 15% improvement in response time just from this. Plus it reduced load on the RDS instance noticeably.
AWS now offers RDS Proxy which does something similar, but PgBouncer gives you more control and costs less.
Redis For Session Management
Odoo stores session data in PostgreSQL by default. Every page load reads and writes session data.
Moving that to Redis took a surprising amount of load off our database. Redis is way faster for this kind of simple read/write operation.
Setup is straightforward. Just install Redis, configure Odoo to use it for sessions, and you're done.
What Actually Moved The Needle
After all this tuning, here's what actually made the biggest difference:
The shared_buffers and effective_cache_size changes cut query time in half. That was the single biggest win.
Finding and fixing those three slow queries probably saved us from having to upgrade to a bigger instance.
PgBouncer improved things noticeably but wasn't as dramatic as the memory settings.
Redis helped, but honestly it was more about offloading PostgreSQL than raw performance gain.
The maintenance stuff like vacuuming and indexing didn't show immediate results, but over time it kept performance from degrading.
How Bithost Can Help
Look, tuning a database is tedious. You need to know what to change, when to change it, and how to measure if it actually helped.
At Bithost, we do this kind of optimization work for companies running everything from small Odoo instances to massive enterprise databases handling millions of transactions daily.
We'll audit your current setup, identify the actual bottlenecks (not just guess), implement the right optimizations, and monitor to make sure they stick.
Whether you're running Odoo on RDS, managing a complex multi-region PostgreSQL setup, or dealing with MySQL performance issues, we've seen it before and know how to fix it.
We also help with ongoing database management so you don't have to become a PostgreSQL expert just to keep your ERP running smoothly.
If your database is slow, your users are complaining, or you're just tired of throwing money at bigger instances without seeing improvement, talk to us.
Sometimes the fix is simple. Sometimes it's complex. Either way, we'll figure it out and get your system running the way it should.
Need database optimization help? Reach out to Bithost at support@bithost.com and let's fix your performance issues.