Skip to content

Fix Odoo 504 Gateway Timeout

DeployMonkey Team · March 11, 2026 7 min read

What Causes a 504 in Odoo

Unlike a 503 (Odoo not running), a 504 Gateway Timeout means Odoo is running but took longer to respond than nginx was willing to wait. The default proxy_read_timeout in nginx is 60 seconds — short enough to catch almost any legitimate slow operation in Odoo.

The three main culprits are:

  • Long-running reports — PDF generation via wkhtmltopdf on large datasets.
  • Slow database queries — missing indexes, table bloat, or unvacuumed tables.
  • nginx proxy_read_timeout too low — legitimate operations that exceed 60 s.

Step 1 — Identify the Slow Operation

Check the Odoo log for the request that timed out:

tail -f /var/log/odoo/odoo.log | grep -E "slow|took|timeout|warning"

Odoo logs a warning for any RPC call exceeding a threshold. You should see something like:

WARNING mydb odoo.service.server: worker timeout (pid:12345)

Note the PID and correlate it with the operation (the preceding log lines will show the model and method being called).

Step 2 — Increase nginx proxy_read_timeout

For report generation, a timeout of 120–300 seconds is reasonable:

# /etc/nginx/sites-enabled/odoo
location / {
proxy_pass         http://127.0.0.1:8069;
proxy_read_timeout 300s;
proxy_connect_timeout 60s;
proxy_send_timeout 300s;
}
sudo nginx -t && sudo systemctl reload nginx

Do not set this to an arbitrarily large value — it masks real problems. 300 s is a sensible ceiling for legitimate Odoo operations.

Step 3 — Tune Odoo Worker Timeouts

Odoo itself kills workers that exceed its own timeout:

# /etc/odoo/odoo.conf
limit_time_cpu = 600
limit_time_real = 1200
limit_time_real_cron = 0

limit_time_real is the wall-clock limit per request. Set it higher than proxy_read_timeout so nginx, not Odoo, is the authority on when to give up on a request.

Step 4 — Find Slow PostgreSQL Queries

Enable pg_stat_statements and look for the worst offenders:

-- In psql connected to your Odoo database:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

SELECT query, calls, mean_exec_time, total_exec_time
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 20;

Queries taking more than 1 second are worth investigating. Common Odoo offenders include:

  • Full table scans on mail_message (add index on res_id, model).
  • Missing index on stock_move.product_id.
  • Unvacuumed tables with high dead-tuple counts.
-- Check for missing autovacuum
SELECT relname, n_dead_tup, last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC LIMIT 20;

-- Force vacuum if needed
VACUUM ANALYZE sale_order;

See Optimize PostgreSQL for Odoo for a complete tuning guide.

Step 5 — Optimise Report Generation

wkhtmltopdf is single-threaded and CPU-bound. For large reports:

  • Run reports during off-peak hours using scheduled actions.
  • Reduce the dataset (add filters before printing).
  • Upgrade to a server with faster single-core performance.
  • Consider the Odoo Enterprise report engine (faster for complex layouts).

Step 6 — Check for Lock Contention

SELECT pid, wait_event_type, wait_event, state, query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock';

If rows appear, a transaction is blocking others. Identify the blocking PID and either wait or terminate it:

SELECT pg_terminate_backend(blocking_pid);

How DeployMonkey Handles Slow Requests

DeployMonkey configures nginx and Odoo timeouts correctly out of the box for every instance. PostgreSQL is co-located on a low-latency SSD volume, and pg_stat_statements is pre-enabled so you can investigate slow queries immediately. The monitoring dashboard surfaces p95 response-time trends so you catch degradation before users do.

Start for free at deploymonkey.app.

Frequently Asked Questions

Should I just set proxy_read_timeout to 3600?

No. A very high timeout means users wait a long time for errors to surface, and nginx worker connections stay open unnecessarily. Fix the underlying slowness instead; use 300 s as a practical ceiling.

Why does the 504 only happen for specific users?

Those users are likely running large reports or accessing data-heavy views (e.g., a sales analysis with years of data). Add filters or pagination to those views.

Can PostgreSQL connection pooling help?

Yes — pgBouncer reduces connection overhead but does not speed up slow queries. It helps when you have many concurrent users exhausting PostgreSQL's max_connections.

How do I tell if it is a network issue vs. a slow query?

Check pg_stat_activity while the slow request is in flight. If you see the query actively running (state = 'active'), it is a slow query. If Odoo is not even querying (idle in transaction), it is application-level processing.