# Session Management in Odoo, Part 2: Beyond Native Sessions

> Add a second Odoo node and users start getting logged out. What session_db, session_redis and auth_session_timeout do, and which one your deployment actually needs.

**Date:** 2026-05-30
**Source:** <https://trobz.com/insights/odoo-session-modules/>

---



You add a second Odoo node to your cluster. Within minutes, users start reporting random logouts. Sessions exist on node A but node B has never seen them.

This post maps the community modules that extend or replace Odoo's native filesystem session store, and the tools available for controlling session lifecycle in production. For readers who skipped [Part 1]({{< surl >}}/insights/odoo-session-internals): native sessions are JSON files on disk, stored under `{data-dir}/sessions/`, one file per session.

---

## When Native Sessions Become a Problem

Odoo's default `FilesystemSessionStore` works well for single-server deployments. Multiple workers on the same machine share the same filesystem, so sessions are always accessible regardless of which worker handles a request [8, Odoo 19.0].

The problem arises in two distinct scenarios.

The first is multi-node clusters. When Odoo runs on two or more machines without a shared filesystem, a session file written on node A is invisible to node B. Any request that lands on a different node than the one that created the session finds no session and forces the user back to the login page. An NFS mount can work around this, but it introduces its own failure modes and performance overhead.

The second is GC latency, a problem that only affects Odoo 15.0 and earlier. On those versions, session garbage collection fired on roughly 1 in 100 requests via `http.session_gc()`: on a server that had accumulated tens of thousands of session files, that directory scan added measurable latency to the unlucky requests that triggered it. Since Odoo 16.0, garbage collection runs in the daily "Base: Auto-vacuum internal data" cron [10], entirely out of the request path, so this latency spike no longer exists on supported versions.

For single-server deployments, native sessions are the right default. The rest of this post is for everyone else.

---

## PostgreSQL-Backed Sessions (`session_db`)

`session_db` is an OCA/server-tools module available for Odoo 13.0-19.0 [1][2]. It replaces `FilesystemSessionStore` with `PGSessionStore`, which stores sessions in a dedicated `http_sessions` table in PostgreSQL.

Activation requires one environment variable:

```
SESSION_DB_URI=postgresql://user:password@host/dbname
```

No code changes are needed. The module monkey-patches `http.root.session_store` at startup, transparently replacing the store for the lifetime of the process [1].

The implementation uses a dedicated PostgreSQL connection, separate from Odoo's ORM connection pool, with automatic retry logic. Each save is an upsert:

```python
INSERT INTO http_sessions(sid, write_date, payload)
    VALUES (%(sid)s, now() at time zone 'UTC', %(payload)s)
ON CONFLICT (sid)
DO UPDATE SET payload = %(payload)s,
              write_date = now() at time zone 'UTC'
```

The `ON CONFLICT DO UPDATE` makes writes idempotent and safe for concurrent workers across multiple nodes [1]. Session data is serialised as JSON, the same format as the filesystem store, so the transition is transparent.

The main reason to choose `session_db` over `session_redis` is operational simplicity: if PostgreSQL is already in your stack, you add no new infrastructure. Every Odoo node already has a PostgreSQL connection configured; `session_db` reuses that dependency rather than introducing a new one.

---

## Redis-Backed Sessions (`session_redis`)

`session_redis` is a Camptocamp module from the `odoo-cloud-platform` repository, available since Odoo 8.0 [3][4][5]. It replaces the session store with `RedisSessionStore`, routing all session reads and writes through Redis.

The minimum configuration to activate it:

```
ODOO_SESSION_REDIS=1
ODOO_SESSION_REDIS_HOST=redis-host
ODOO_SESSION_REDIS_PORT=6379
```

A URL form is also available: `ODOO_SESSION_REDIS_URL=redis://...`. Optional variables include `ODOO_SESSION_REDIS_PASSWORD` and `ODOO_SESSION_REDIS_PREFIX`, which is useful when multiple Odoo instances share a single Redis server.

### Session TTLs

One important feature is separate TTL control for authenticated and anonymous sessions [3]:

```
ODOO_SESSION_REDIS_EXPIRATION=86400         # authenticated, in seconds (1 day)
ODOO_SESSION_REDIS_EXPIRATION_ANONYMOUS=3600  # anonymous, in seconds (1 hour)
```

The right values depend on your use case. On a standard back-office deployment, anonymous sessions are created by monitoring probes, health checks, and unauthenticated API calls. Keeping them for only an hour or so is sufficient and avoids accumulating thousands of short-lived sessions in Redis. Authenticated users log in once a day and expect their session to survive the working day, so 24 hours is a reasonable default.

On an e-commerce site the trade-off shifts. Anonymous sessions carry the visitor's cart and wishlist. Expiring them after an hour means a returning visitor who did not log in loses their cart. In that context, setting `ODOO_SESSION_REDIS_EXPIRATION_ANONYMOUS` to a longer value (24 hours or more) avoids that friction.

### Redis Sentinel

Redis Sentinel is supported for high-availability Redis setups. Three additional variables are required when using it: `ODOO_SESSION_REDIS_SENTINEL_HOST`, `ODOO_SESSION_REDIS_SENTINEL_PORT`, and `ODOO_SESSION_REDIS_SENTINEL_MASTER_NAME`. All three must be set together [4].

### Redis vs PostgreSQL

Compared to `session_db`, Redis has lower read latency (in-memory, no SQL round-trip) and handles key expiry natively without a cleanup cron. It is the better fit for very high request volumes where session reads happen on every request, or when a Redis cluster is already part of the infrastructure. If neither of those applies, `session_db` is simpler to operate.

---

## Session Lifecycle Management

### Inactivity-Based Logout

`auth_session_timeout` is an OCA/server-auth module available for Odoo 12.0-19.0 [7]. It automatically terminates sessions that have been inactive beyond a configurable threshold. The threshold is set via a system parameter in Odoo's settings: 2h by default.

This module is independent of the storage backend: it works whether sessions are stored on the filesystem, in PostgreSQL, or in Redis. It is most relevant for security-sensitive deployments: regulated environments, shared workstations, or public-facing Odoo instances where indefinitely open browser sessions are a risk.

Since Odoo 16.0, native Odoo covers part of this ground: the `sessions.max_inactivity_seconds` system parameter shortens the session expiry (and on recent versions the cookie lifetime as well) without any module. The difference is enforcement timing: the native parameter only takes effect when the daily GC cron reaps the session file, while `auth_session_timeout` checks inactivity on every request and logs the user out immediately. For strict timeout requirements, the module remains the right tool.

### Force-Logout API

For cases where inactivity-based expiry is not enough, Trobz contributed `auth_session_logout_api` to OCA/server-auth [9]. The module exposes a secure API endpoint that allows remote force-logout of a specific user session. As of May 2026 the PR targets Odoo 16.0 and is pending merge — check [9] for current status.

### Deterministic GC: Past Module, Now Native

The random GC latency problem described in the first section was solved by `base_deterministic_session_gc`, a module authored by Trobz and contributed to OCA/server-tools for Odoo 12.0-14.0 [6]. It disabled `http.session_gc()` and replaced it with a scheduled cron action, making cleanup predictable and removing it from the request path entirely. The module required `server_wide_modules` configuration to load at startup.

Since Odoo 16.0, this design is native: session GC runs in `_gc_sessions()`, part of the daily "Base: Auto-vacuum internal data" cron, and the per-request `http.session_gc()` is gone [10]. The inactivity threshold is configurable via the `sessions.max_inactivity_seconds` system parameter. No module or extra configuration is needed.

The `ODOO_SKIP_GC_SESSIONS` environment variable still exists in 16.0+, but its meaning is the opposite of what its history suggests: it skips the built-in cron GC entirely [10]. Set it only when session cleanup is handled elsewhere, for example by the TTL mechanism of `session_redis`, a custom cleanup job on the `http_sessions` table for `session_db`, or platform-level tooling.

---

## Which Approach for Your Deployment

**Single server, any number of workers**: native filesystem sessions are sufficient. Add `auth_session_timeout` if immediate inactivity-based logout is a security requirement; for a softer expiry, shorten `sessions.max_inactivity_seconds` (16.0+).

**Multi-node cluster**: `session_db` or `session_redis` is required. The choice depends on existing infrastructure. PostgreSQL already in the stack and no extreme session read throughput: use `session_db`. Redis already present, or session reads are on the critical path at high volume: use `session_redis`.

**Security-sensitive deployment**: add `auth_session_timeout` regardless of the storage backend. It is orthogonal to where sessions are stored. For deployments that also need immediate remote logout, watch `auth_session_logout_api` for merge into OCA [9].

---

## Key Takeaways

Odoo's native filesystem sessions are production-ready for single-server deployments. For multi-node clusters, `session_db` and `session_redis` each provide cross-node session sharing with minimal configuration: one environment variable to activate, no code changes. `auth_session_timeout` is a drop-in addition for inactivity-based logout regardless of storage backend. The random GC latency problem that `base_deterministic_session_gc` once solved is fixed natively since Odoo 16.0, where session GC runs in the daily auto-vacuum cron instead of the request path.

**Back to the series:** [Part 1]({{< surl >}}/insights/odoo-session-internals) covers the session object, filesystem storage, and the HMAC-based security model in detail. [Part 3]({{< surl >}}/insights/odoo-session-faq) is a FAQ answering the session questions we hear most often in production.

---

## Sources

[1] `server-tools/18.0/session_db/pg_session_store.py:62-167` (OCA/server-tools)

[2] `server-tools/18.0/session_db/README.rst` (OCA/server-tools)

[3] `session_redis/session.py:20-127` (Camptocamp/odoo-cloud-platform)

[4] `session_redis/http.py:24-90` (Camptocamp/odoo-cloud-platform)

[5] `session_redis/README.rst` (Camptocamp/odoo-cloud-platform)

[6] `server-tools/14.0/base_deterministic_session_gc/http.py:15-42` (OCA/server-tools)

[7] `server-auth/18.0/auth_session_timeout/__manifest__.py:1-21` (OCA/server-auth)

[8] `odoo/http.py:968-1048` (Odoo 19.0 native FilesystemSessionStore)

[9] OCA/server-auth PR #891: `auth_session_logout_api` (Trobz, targeting 16.0, pending merge)

[10] `odoo/addons/base/models/ir_http.py:406-410` (Odoo 19.0, `_gc_sessions()` autovacuum cron, `ODOO_SKIP_GC_SESSIONS`)

