diff --git a/documentation/enterprise-kubernetes-operator/getting-started/aws.md b/documentation/enterprise-kubernetes-operator/getting-started/aws.md
index e386ede14..646c82086 100644
--- a/documentation/enterprise-kubernetes-operator/getting-started/aws.md
+++ b/documentation/enterprise-kubernetes-operator/getting-started/aws.md
@@ -491,7 +491,7 @@ kubectl annotate serviceaccount default \
The manifest below connects QuestDB to your S3 bucket and starts one instance
with a backup every five minutes.
-Keep the QuestDB ECR account ID unchanged. The tested image tag for v0.3.1 is
+Keep the QuestDB ECR account ID unchanged. The tested image tag for v0.4.0 is
`4.0.1-enterprise`; change it only when QuestDB provides another one.
```sh
diff --git a/documentation/enterprise-kubernetes-operator/getting-started/azure.md b/documentation/enterprise-kubernetes-operator/getting-started/azure.md
index 318c43ee7..04950e091 100644
--- a/documentation/enterprise-kubernetes-operator/getting-started/azure.md
+++ b/documentation/enterprise-kubernetes-operator/getting-started/azure.md
@@ -327,7 +327,7 @@ You should see a successful rollout followed by all three CRDs.
You're ready to create QuestDB. The manifest below connects it to your Blob
container and starts one instance with a backup every five minutes.
-It uses the tested v0.3.1 `4.0.1-enterprise` image. Change the tag only when
+It uses the tested v0.4.0 `4.0.1-enterprise` image. Change the tag only when
QuestDB provides another one.
```sh
diff --git a/documentation/enterprise-kubernetes-operator/reference/api.md b/documentation/enterprise-kubernetes-operator/reference/api.md
index 83f99c35d..234e45da6 100644
--- a/documentation/enterprise-kubernetes-operator/reference/api.md
+++ b/documentation/enterprise-kubernetes-operator/reference/api.md
@@ -3,8 +3,8 @@ title: Kubernetes Operator API reference
description: Custom resources provided by the QuestDB Enterprise Kubernetes Operator.
---
-
+
# API Reference
Packages:
@@ -224,6 +224,15 @@ legitimate day-2 operation that strands nothing (see the spec-level rules).
Validations:
- self == oldSelf: spec.objectStoreRef is immutable
false |
+
+ | podMetadata |
+ object |
+
+ podMetadata adds labels and annotations to every instance Pod (e.g. scrape
+annotations for a metrics agent). Operator-owned keys always win. Changing it
+rolls the Pods, including the primary.
+ |
+ false |
| protocols |
object |
@@ -875,6 +884,42 @@ reference. Which kind is determined by the field: see its documentation.
+### QuestDBCluster.spec.podMetadata
+[↩ Parent](#questdbclusterspec)
+
+
+
+podMetadata adds labels and annotations to every instance Pod (e.g. scrape
+annotations for a metrics agent). Operator-owned keys always win. Changing it
+rolls the Pods, including the primary.
+
+
+
+
+ | Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ | annotations |
+ map[string]string |
+
+
+ |
+ false |
+
+ | labels |
+ map[string]string |
+
+
+ |
+ false |
+
+
+
+
### QuestDBCluster.spec.protocols
[↩ Parent](#questdbclusterspec)
@@ -3064,8 +3109,10 @@ podDisruptionBudget tunes the operator-managed PodDisruptionBudget.
enabled |
boolean |
- enabled controls whether the operator maintains a PDB. Defaults to true.
-Set false to remove the PDB entirely (e.g. to permit unrestricted node drains).
+ enabled controls whether the operator maintains a PDB. When unset, a
+replicated cluster (instances > 1) gets one and a single-instance cluster does
+not, unless minAvailable is set. Set false to remove the PDB entirely (e.g. to
+permit unrestricted node drains).
|
false |
@@ -3073,15 +3120,16 @@ Set false to remove the PDB entirely (e.g. to permit unrestricted node drains).<
| integer |
minAvailable overrides the computed integer minAvailable. When unset:
-single instance => 1; replicated => instances-1.
+replicated => instances-1; single instance => 1 if the PDB is enabled.
LIMITATION: instance Pods have no controller to reschedule them, so a PDB
that leaves no disruption budget HARD-BLOCKS voluntary evictions (`kubectl
drain` hangs) until a human deletes the Pod or the PDB. This happens whenever
-minAvailable >= the number of currently-Ready instances — including the
-single-instance default (minAvailable=1 over one Pod). It is intentional
-protection for a database, NOT auto-clamped: set a lower minAvailable, scale
-out, or disable the PDB if you need drains to proceed unattended.
+minAvailable >= the number of currently-Ready instances — which is why a
+single-instance cluster gets no PDB by default: a drain evicts its only Pod
+(a short outage) and the operator recreates it on another node. It is NOT
+auto-clamped: set a lower minAvailable, scale out, or disable the PDB if you
+need drains to proceed unattended.
Format: int32
Minimum: 0
diff --git a/documentation/enterprise-kubernetes-operator/releases.md b/documentation/enterprise-kubernetes-operator/releases.md
index 7f5e47321..a00e2a3aa 100644
--- a/documentation/enterprise-kubernetes-operator/releases.md
+++ b/documentation/enterprise-kubernetes-operator/releases.md
@@ -3,8 +3,8 @@ title: Kubernetes Operator releases
description: Release history for the QuestDB Enterprise Kubernetes Operator.
---
-
+
# Changelog
Notable changes to the QuestDB Enterprise Operator are documented here.
@@ -12,20 +12,20 @@ Notable changes to the QuestDB Enterprise Operator are documented here.
## Latest operator artifacts
-Latest stable release: **0.3.1**
+Latest stable release: **0.4.0**
### Operator images
**AWS ECR**
```text
-695242380269.dkr.ecr.eu-west-1.amazonaws.com/questdb-enterprise-operator:0.3.1
+695242380269.dkr.ecr.eu-west-1.amazonaws.com/questdb-enterprise-operator:0.4.0
```
**Non-AWS mirror**
```text
-registry.distribution.questdb.io/questdb-enterprise-operator:0.3.1
+registry.distribution.questdb.io/questdb-enterprise-operator:0.4.0
```
Both references require the registry access supplied by QuestDB.
@@ -37,10 +37,51 @@ Both references require the registry access supplied by QuestDB.
```sh
helm install questdb-operator oci://ghcr.io/questdb/charts/questdb-operator \
--namespace questdb-operator-system --create-namespace \
- --version 0.3.1
+ --version 0.4.0
```
+## [0.4.0] - 2026-10-16
+
+### Upgrade notes
+
+- Single-instance clusters no longer get a PodDisruptionBudget by default.
+ After the upgrade, draining the node (or a managed node upgrade on AKS or
+ EKS) restarts the database on another node instead of blocking forever. To
+ keep the old behaviour, set
+ `spec.scheduling.podDisruptionBudget.enabled: true`. Replicated clusters are
+ unchanged.
+- If you manage CRDs yourself (`crd.enable=false`), apply this release's CRDs
+ before upgrading the operator, so `spec.podMetadata` is accepted.
+
+### Added
+
+- `spec.podMetadata` adds your own labels and annotations to every QuestDB
+ Pod, for example metrics-scrape annotations:
+
+ ```yaml
+ podMetadata:
+ annotations:
+ k8s.grafana.com/scrape: "true"
+ ```
+
+ The operator's own labels always win. Changing `podMetadata` restarts the
+ Pods one at a time, like a `scheduling` change.
+
+### Changed
+
+- When a rolling update is waiting, the `Progressing` condition says why and
+ on which instance, for example
+ `waiting: PeerNotReady on instance prod-3`.
+
+### Fixed
+
+- A replica whose PVC was deleted now rebuilds itself. Before, if its Pod came
+ back before the PVC was gone, the PVC stayed `Terminating` and the replica
+ never recovered.
+- The operator is built with Go 1.26.9 and updated dependencies, fixing
+ reported CVEs.
+
## [0.3.1] - 2026-09-28
### Upgrade notes
|