Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions documentation/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This page tracks significant updates to the QuestDB documentation.

### New

- [ACL audit log](/docs/security/acl-audit-log/) - Documented the access control audit log introduced in QuestDB Enterprise 4.2.0, including principal attribution, read permissions, redaction, delivery guarantees, WAL availability troubleshooting, change-ID recovery limits, replication, and retention
- [Expiring rows (`EXPIRE ROWS`)](/docs/concepts/expire-rows/) and [ALTER MATERIALIZED VIEW SET EXPIRE](/docs/query/sql/alter-mat-view-set-expire/) - Keep only some rows in a materialized view. Set it when you create the view (see [CREATE MATERIALIZED VIEW](/docs/query/sql/create-mat-view/)) or add it later. Queries hide expired rows right away, and a background job frees their disk space for the policies where that is safe.
- [GROUPING SETS, ROLLUP, and CUBE](/docs/query/sql/grouping-sets/) - Compute detail rows, subtotals, and a grand total in a single scan, with `GROUP BY` or `SAMPLE BY`. Covers composite syntax, `GROUPING()` and `GROUPING_ID()`, `FILL` support, parallel execution, when a `UNION ALL` of plain `GROUP BY` queries is faster, and the limitations, plus the [`cairo.sql.max.grouping.sets`](/docs/configuration/cairo-engine/#cairosqlmaxgroupingsets) setting
- [Reports with subtotals and grand totals](/docs/cookbook/sql/advanced/subtotals-and-grand-totals/) - Cookbook recipe for a desk volume report with per-ECN subtotals and a grand total from `ROLLUP`, labelled with `GROUPING()`, plus totals in both directions with `CUBE` and hourly totals with `SAMPLE BY`
Expand All @@ -21,6 +22,7 @@ This page tracks significant updates to the QuestDB documentation.

- Added [`qwp.min.idle.ms.before.writer.release`](/docs/configuration/qwp/#qwpminidlemsbeforewriterrelease), which sets how long an idle QWP WebSocket ingestion connection holds its table writers before QuestDB releases them
- [`acl.oidc.pkce.required`](/docs/configuration/oidc/#acloidcpkcerequired) - Corrected the PKCE setting name. The page listed `acl.oidc.pkce.enabled`, which the server rejects as unrecognized, leaving PKCE at its default of `true`
- [IAM configuration](/docs/configuration/iam/#aclauditstoragepolicy) - Documented `acl.audit.storage.policy`, introduced in QuestDB Enterprise 4.2.0, including its creation-only behavior, partition-start-based conversion and deletion eligibility, supported stages, and built-in-admin requirements for changing an existing log's policy

### Updated

Expand All @@ -45,6 +47,11 @@ This page tracks significant updates to the QuestDB documentation.
capped set. Likewise, move a window function into the query you run against
the view.

- [CREATE SERVICE ACCOUNT](/docs/query/sql/acl/create-service-account/) - Documented the QuestDB Enterprise 4.2.0 change that leaves an existing account unchanged under `IF NOT EXISTS`, with explicit assignment through `GRANT ASSUME SERVICE ACCOUNT` and [upgrade guidance](/docs/operations/upgrade/#service-account-creation)
- [Backup and restore](/docs/operations/backup/#retrying-or-updating-a-restore) - Distinguished fresh restores from same-lineage retries and forward updates, with their procedures and restrictions, and documented [access control recovery](/docs/operations/backup/#restoring-access-control-tables) from backups taken before the ACL audit log was introduced in QuestDB Enterprise 4.2.0
- [Governance and auditing](/docs/security/governance/#audit-access-control-changes) - Added an ACL audit query covering ordinary grants and revokes as well as service-account assumption assignments and revocations
- [Storage policy](/docs/concepts/storage-policy/#ttl-evaluation) - Corrected partition-start eligibility across audit retention, TTL migration, Parquet conversion, and Enterprise quick-start guidance, with partition allowances for minimum timestamp-based retention and clearer governance example thresholds

## October 2026

### Releases
Expand Down
13 changes: 10 additions & 3 deletions documentation/concepts/parquet.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,20 @@ A policy can be attached when creating the table with the `STORAGE POLICY`
clause on [`CREATE TABLE`](/docs/query/sql/create-table/#storage-policy), or set
later with
[`ALTER TABLE SET STORAGE POLICY`](/docs/query/sql/alter-table-set-storage-policy/).
For example, convert a partition to Parquet one hour after it stops being the
active partition:
For example, make an inactive partition eligible when the
[reference time](/docs/concepts/storage-policy/#ttl-evaluation) is at least one
hour after the partition's start:

```questdb-sql title="Convert to Parquet after 1 hour (Enterprise)"
```questdb-sql title="Set a one-hour Parquet conversion threshold"
ALTER TABLE market_data SET STORAGE POLICY(TO PARQUET 1h);
```

For hourly partitions, this threshold can be met as soon as the next partition
becomes active; there is no extra one-hour wait. The active partition never
converts, and eligible conversions run asynchronously. By default, the reference
time is the earlier of the latest table timestamp and the wall clock, so a quiet
table can delay conversion.

The TTL unit cannot be finer than the table's partition size (`market_data` is
partitioned by hour). See the [Storage Policy](/docs/concepts/storage-policy/)
concept guide for the full partition lifecycle, including `DROP LOCAL`.
Expand Down
50 changes: 35 additions & 15 deletions documentation/concepts/storage-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,22 @@ late-arrival, replay, and correction window for the table. See

### TTL evaluation

Storage policy TTLs follow the same evaluation rules as
[TTL](/docs/concepts/ttl/). A partition becomes eligible for a lifecycle action
when its **entire time range** falls outside the TTL window:
Storage policy TTLs measure age from the partition's start. This differs from
[table TTL](/docs/concepts/ttl/), which measures from the end of the partition
and waits until its entire time range is outside the retention window. For
hour-, day-, and week-based durations, a partition becomes eligible when:

```text
eligible when: partition_end_time < reference_time - TTL
reference_time - partition_start_time >= TTL
```

**This rule is applied independently for each stage's TTL.** A partition can
be eligible for `TO PARQUET` long before it is eligible for `TO REMOTE`,
`DROP LOCAL`, or `DROP REMOTE`. Each stage uses its own `TTL` in the formula
above; the stages share only the reference time and the
Month- and year-based durations compare elapsed calendar months from the same
partition-start boundary.

Every stage uses this boundary, including `DROP LOCAL` and `DROP REMOTE`, but
each evaluates its own TTL independently. A partition can be eligible for
`TO PARQUET` long before it is eligible for `TO REMOTE`, `DROP LOCAL`, or
`DROP REMOTE`. The stages share the reference time and the
[ordering constraints](#ordering-constraint).

The reference time is `min(wall_clock_time, latest_timestamp)` by default —
Expand All @@ -113,7 +117,19 @@ the wall-clock cap for both TTL and storage policy evaluation. See
and the data-loss hazard of disabling the cap.

QuestDB checks storage policies periodically (every 5 minutes by default) and
processes eligible partitions automatically.
processes eligible partitions automatically. A quiet table may retain partitions
longer because its latest timestamp, and therefore the reference time, stops
advancing.

:::warning Minimum row retention

A stage's TTL is not a minimum age for every row in the partition. With daily
partitions, `DROP LOCAL 365d` can delete a row near the end of a partition almost
a day before that row is 365 days old. For a minimum 365-day timestamp-based
retention window, use `DROP LOCAL 366d` to include a one-day partition allowance.
This window is based on the designated timestamp, not the time since ingestion.

:::

## Storage policy vs TTL

Expand All @@ -130,16 +146,20 @@ you are already familiar with TTL, this comparison is the fastest way in:
In QuestDB Enterprise, use storage policies instead of TTL. On a regular table,
`ALTER TABLE SET TTL` with a non-zero value is rejected, while
`CREATE TABLE ... TTL` is accepted only for backward compatibility and is
translated into a `STORAGE POLICY(DROP LOCAL ...)`:
translated into a `STORAGE POLICY(DROP LOCAL ...)`.

```questdb-sql
-- Instead of:
-- ALTER TABLE trades SET TTL 30 DAYS;
For a daily-partitioned `trades` table, preserving the minimum 30-day
timestamp-based retention window of `TTL 30 DAYS` requires a one-day
[partition allowance](#ttl-evaluation):

-- Use:
ALTER TABLE trades SET STORAGE POLICY(DROP LOCAL 30d);
```questdb-sql title="Preserve 30-day retention with daily partitions"
ALTER TABLE trades SET STORAGE POLICY(DROP LOCAL 31d);
```

For other partition intervals or calendar-month/year durations, calculate the
threshold from the [partition-start rule](#ttl-evaluation) rather than copying
the old TTL value.

:::note

A table can carry a TTL if it was created in QuestDB Open Source and later
Expand Down
10 changes: 6 additions & 4 deletions documentation/configuration/audited-views.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ None of these settings are reloadable: changing any of them requires a restart.
The server checks the values at startup, and refuses to start, naming the
property, when a numeric value is out of range.

For example, to absorb longer bursts of audited reads and keep 90 days of the
trail:
For example, to absorb longer bursts of audited reads and delete daily
partitions using a 90-day partition-age threshold:

```ini title="server.conf"
view.audit.queue.capacity=16384
Expand Down Expand Up @@ -82,8 +82,10 @@ same log message.
[Storage policy](/docs/concepts/storage-policy/) that `sys.view_audit` is
created with. The value is the list of stages written inside
`SET STORAGE POLICY(...)`, separated by commas, such as
`TO PARQUET 1d, DROP LOCAL 90d`. The default converts each daily partition to
Parquet one day after the partition ends, and never deletes a row.
`TO PARQUET 1d, DROP LOCAL 90d`. The default never deletes rows. It makes
inactive daily partitions eligible for Parquet conversion when the
[reference time](/docs/concepts/storage-policy/#ttl-evaluation) is at least one
day after the partition's start, not its end. Conversion runs asynchronously.

- The setting applies only when the server creates the table. Replicas take the
table, and its policy, from the primary.
Expand Down
135 changes: 100 additions & 35 deletions documentation/configuration/iam.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
---
title: Identity and Access Management (IAM)
sidebar_label: Identity and Access Management
description: Configuration settings for Identity and Access Management in QuestDB Enterprise.
title: Identity and access management (IAM)
sidebar_label: Identity and access management
description:
Configuration settings for Identity and Access Management in QuestDB
Enterprise.
---

:::note
Expand All @@ -13,11 +15,14 @@ Identity and Access Management is available within

Identity and Access Management (IAM) controls authentication and authorization
for all QuestDB interfaces. These settings cover the built-in admin user,
password hashing, and REST token behavior.
password hashing, REST token behavior, ACL audit retention, and permission
compaction.

For a full explanation of IAM, see the
[Identity and Access Management (IAM) documentation](/docs/security/rbac).

## Authentication and authorization

### acl.admin.password

- **Default**: `quest`
Expand All @@ -44,8 +49,8 @@ Enables or disables the built-in admin user.
- **Default**: `false`
- **Reloadable**: no

When enabled, the browser's basic auth popup window is used instead of the
Web Console's login screen. Present for backwards compatibility only.
When enabled, the browser's basic auth popup window is used instead of the Web
Console's login screen. Present for backwards compatibility only.

### acl.enabled

Expand All @@ -54,30 +59,6 @@ Web Console's login screen. Present for backwards compatibility only.

Enables or disables Identity and Access Management.

### acl.permissions.compaction.row.threshold

- **Default**: `10000`
- **Reloadable**: no

Number of rows in `sys.acl_permissions` above which the table is compacted.
Set to `0` or below to disable compaction.

`sys.acl_permissions` is an append-only log of grants and revokes, collapsed
at read time to give each entity its current permissions. A deployment that
re-grants on a schedule accumulates rows indefinitely, and past a certain size
every replicated `GRANT` makes a replica reload a progressively larger access
list, slowing logins. Compaction rewrites the log to keep only the rows that
still matter.

### acl.permissions.compaction.startup.delay

- **Default**: `300000`
- **Reloadable**: no

Grace period in milliseconds before the backlog check runs after a boot or a
promotion. The delay keeps compaction from competing with a node that is still
starting up or taking over as primary.

### acl.entity.name.max.length

- **Default**: `255`
Expand All @@ -91,8 +72,8 @@ Maximum length of user, group, and service account names.
- **Reloadable**: no

Number of hash iterations used in password hashing. QuestDB Enterprise never
stores passwords in plain text. Higher values are safer but slower. This
should almost never be changed.
stores passwords in plain text. Higher values are safer but slower. This should
almost never be changed.

### acl.rest.token.refresh.threshold

Expand All @@ -101,12 +82,96 @@ should almost never be changed.

When a REST token is created in REFRESH mode, its TTL is extended on every
successful authentication, unless the last authentication was within this
threshold (in seconds). Removes unnecessary overhead of continuously
refreshing tokens that are used frequently.
threshold (in seconds). Removes unnecessary overhead of continuously refreshing
tokens that are used frequently.

### line.tcp.acl.enabled

- **Default**: `true`
- **Reloadable**: no

Enables or disables authentication for the ILP over TCP endpoint only.
Enables or disables authentication for the ILP over TCP endpoint only. Keep it
enabled to enforce write protections on system-managed tables, including the
[ACL audit log](/docs/security/acl-audit-log/#protection-and-administration).

## ACL audit log

### acl.audit.storage.policy

- **Default**: `TO PARQUET 1d`
- **Reloadable**: no

Available in QuestDB Enterprise 4.2.0 and later.

[Storage policy](/docs/concepts/storage-policy/) used when the server creates
`sys.acl_audit_log`. The value is a comma-separated list of stages, without
surrounding parentheses.

The default policy, `TO PARQUET 1d`, never deletes rows. It makes inactive daily
partitions eligible for Parquet conversion when the reference time is at least
one day after the partition's start, not its end. By default, the reference time
is the earlier of the latest audit timestamp and the wall clock. Conversion runs
asynchronously.

Add `DROP LOCAL` to delete older audit evidence automatically. It uses the same
[partition-start rule](/docs/concepts/storage-policy/#ttl-evaluation) as
conversion: with daily partitions, `DROP LOCAL 365d` can delete a row almost a
day before it is 365 days old. For a minimum 365-day retention window based on
`change_id`, include a one-day partition allowance:

```ini title="server.conf: 365-day minimum timestamp-based retention"
acl.audit.storage.policy=TO PARQUET 1d, DROP LOCAL 366d
```

This is timestamp-based retention, not elapsed time since a change was recorded.
A quiet log may retain partitions longer while its latest timestamp does not
advance.

- Only `TO PARQUET` and `DROP LOCAL` are supported. `TO REMOTE` and
`DROP REMOTE` are rejected.
- Set the property on every node before the table is first created. Replicas
normally receive the primary's table and policy, but a replica promoted before
receiving the table creates it using its own setting.
- Changing this setting does not change an existing table's policy, even after a
restart. Only the built-in admin can change it with
[`ALTER TABLE SET STORAGE POLICY`](/docs/query/sql/alter-table-set-storage-policy/).
- An empty value creates the table without a policy. If the policy is rejected,
the server logs the error and creates the table without it. Check the result
with `SHOW CREATE TABLE 'sys.acl_audit_log'`.
- On a database restored from a backup, creation of the log and its policy can
be deferred to preserve restore compatibility. See
[Restoring access control tables](/docs/operations/backup/#restoring-access-control-tables).

See [ACL audit log retention](/docs/security/acl-audit-log/#retention) for
administration when the built-in admin is disabled.

## Permission compaction

### acl.permissions.compaction.row.threshold

- **Default**: `10000`
- **Reloadable**: no

Number of rows in `sys.acl_permissions` above which the table is compacted. Set
to `0` or below to disable compaction.

`sys.acl_permissions` is an append-only log of grants and revokes, collapsed at
read time to give each entity its current permissions. A deployment that
re-grants on a schedule accumulates rows indefinitely, and past a certain size
every replicated `GRANT` makes a replica reload a progressively larger access
list, slowing logins. Compaction rewrites the log to keep only the rows that
still matter.

Archived rows in `sys.acl_permissions_history` retain their `change_id`, which
links them to the
[ACL audit log](/docs/security/acl-audit-log/#link-changes-to-acl-rows),
provided the history table has the column.

### acl.permissions.compaction.startup.delay

- **Default**: `300000`
- **Reloadable**: no

Grace period in milliseconds before the backlog check runs after a boot or a
promotion. The delay keeps compaction from competing with a node that is still
starting up or taking over as primary.
Loading
Loading