Upgrade AISIX Enterprise
AISIX Enterprise upgrades the control plane first and the gateways second. Existing gateways continue serving traffic while you upgrade and verify the control plane, then you can roll out the matching gateway release in stages.
The procedure differs for package and Helm installations, but both paths require the same preparation. Review every intervening release, create a complete recovery set, and decide how you will verify or roll back the deployment. For OpenShift or OKD, follow Upgrade AISIX Enterprise on OpenShift or OKD.
Plan the Upgrade
An AISIX Enterprise control plane at 1.6.0 or later can upgrade directly to a later release. You do not need to install each intermediate release, but you must complete the applicable upgrade actions from every release you skip.
A control plane older than 1.6.0 cannot upgrade directly to this release. cp-api refuses to start on a database that a control plane older than 1.6.0 last ran, before it changes anything in the database, and the package's run.sh refuses the same upgrade. Upgrade such a control plane to 1.6.x or 1.7.x first, let it start and finish its database migrations, and then upgrade to this release.
Both refusals name the source version and the oldest supported one. cp-api judges the version that control planes from 1.2.0 record in the database. A database last run by an earlier release carries no record and is not refused by cp-api, so confirm the source version yourself before a Helm upgrade; the package's run.sh reads it from .env instead.
Because run.sh reads .env, its check passes whenever .env pins a newer release than the one that last ran the database, such as after restoring an older database backup or setting AISIX_VERSION by hand. cp-api then refuses on the version the database records, before migrating anything, and run.sh reports that version. Before taking the two-step path, set AISIX_VERSION in .env back to the version it names and remove any AISIX_API_IMAGE or AISIX_DPM_IMAGE pin, so that the intermediate package upgrades from that version instead of refusing a downgrade.
To proceed anyway, take a database backup first. For a package installation, set the variable to exactly 1 on the command line; run.sh passes it to cp-api, so both checks allow the upgrade:
AISIX_ALLOW_UNSUPPORTED_UPGRADE=1 ./run.sh
For a package upgraded this way from 1.5.x or earlier, run.sh also removes that release's separate ui dashboard container, which the package no longer defines.
Do not put it in .env, where it would stay on for every later start. For a Helm installation, set api.allowUnsupportedUpgrade: true in the values file used for the upgrade, and remove it after the upgrade.
Use this sequence for both package and Helm installations:
- Read the release notes from the release after your source version through the target version.
- Complete the source-specific preparation.
- Create and verify a recovery set containing the database, secrets, deployment configuration, and matching software.
- Upgrade the control plane by following the package or Helm procedure on this page.
- Verify the control plane, then complete any required source-specific action, such as consolidating multiple organizations.
- Upgrade each gateway release and monitor the deployment through your normal observation period.
- Complete optional cleanup only after the rollback window closes.
Mixed-Version Behavior
During the rollout, the control plane can run a newer release than its gateways. This allows a staged fleet upgrade, but a setting introduced after an older gateway release might not take effect there. The oldest gateway release the control plane supports is 1.6.0.
| What happens | Control-plane behavior | Operator action |
|---|---|---|
| An older gateway can load the resource but does not recognize one field. | The save succeeds with a warning that identifies the field, affected gateway versions, and affected count. | Do not rely on that field until the affected gateways are upgraded. This is especially important for restrictive settings. |
| An older gateway cannot load the resource. | The save fails with HTTP 422 and DP_INCOMPATIBLE. Nothing is written. | Upgrade the affected gateways or leave the incompatible setting out. |
| A gateway runs a release older than 1.6.0. | The save is not checked against that gateway. It succeeds with a warning that names the affected gateway versions, and Data planes marks the gateway Unsupported version. The gateway may fail to load the saved configuration. | Upgrade the gateway to 1.6.0 or later. |
| A gateway registers or rolls back after the save, or reports an unrecognized version. | The earlier save might not have been checked against that gateway. | Verify the runtime state in the environment overview and Data planes view. See Resource Projection. |
Gateway versions are shown per instance in Data planes. The control-plane version appears at the bottom of the dashboard navigation and is returned by the public configuration endpoint. See Verify the Deployment.
A restarted gateway can remain in the compatibility check for up to five minutes. If a save is refused for a release you have already replaced, wait for the old registration to expire and retry.
Prepare for Version-Specific Changes
Before running the package or Helm procedure, identify every row that applies to the release you are upgrading from. The rows are cumulative: an upgrade from 1.6.x follows the 1.6.x and 1.7.0 rows, and a Helm release first installed with chart 1.5.0 also follows the chart 1.5.0 row.
| Source release | Before upgrading | After upgrading |
|---|---|---|
| 1.5.x or earlier | Upgrade to 1.6.x or 1.7.x first, after you prepare sign-in, dashboard, and organization changes. | If more than one organization remains, consolidate them into one, then verify access. |
| 1.6.x or earlier | Replace the retired per-connection SSRF settings. | Verify every required private destination remains reachable. |
| 1.7.0 or earlier | Prepare the database role and connection. | Remove obsolete database privileges and roles after the rollback window closes. |
| A Helm release first installed with chart 1.5.0 | Move the settings and Service consumers that chart 1.5.0 used. | Verify sign-in and dashboard access through the control-plane API Service. |
From 1.5.x or Earlier: Prepare Sign-In, Dashboard, and Organizations
A control plane at 1.5.x or earlier upgrades in two steps: first to 1.6.x or 1.7.x, then to this release. The preparation in this section applies to the first step, which moves sign-in and the dashboard into the control-plane API, removes Google and GitHub sign-in, and limits AISIX Enterprise to one organization. Before that first upgrade:
- Identify users who signed in only with Google or GitHub. They have no password; after the upgrade, an administrator must enable sign-in or reset their password.
- Existing sessions end during the upgrade. Accounts, passwords, ownership, and administrator roles remain; users with passwords sign in again with the same credentials. Rolling back ends the sessions created after the upgrade.
- Update any non-dashboard sign-up client to send the invitation's
invitationToken. A request that sends only the person's account details is refused after the upgrade. - Inventory every organization, its owners, and the users and resources that must be retained. Decide which organization will remain after the upgrade.
Review these deployment settings as part of the same preparation:
| Existing configuration | Required action |
|---|---|
secrets.betterAuthSecret, BETTER_AUTH_SECRET, and BETTER_AUTH_URL | Preserve them while rollback to 1.5.x remains possible. The target release does not use them. |
AISIX_TRUSTED_ORIGINS in ui.extraEnvVars | Move the setting to api.trustedOrigins. Charts 1.6.x and 1.7.x still pass that value to the control-plane API; later charts do not. |
AISIX_DASHBOARD_LOCALE on the old dashboard container | Set ui.defaultLocale or AISIX_CLOUD_DEFAULT_LOCALE instead. |
| A private database CA mounted only on the old dashboard workload | Configure externalDatabase.sslRootCert so the control-plane API and data-plane manager receive it. |
The separate aisix-cp-ui image | Keep it available during the rollback window. Remove it from image mirrors and allow-lists afterwards. |
Charts 1.6.x and 1.7.x keep the <release>-ui Service, with the same name, type, port, and node port, and select the control-plane API pods, so a reverse proxy or NodePort that still points at that Service keeps working through the first step. Later charts remove it; see Helm Releases First Installed with Chart 1.5.0. The package removes the old dashboard container during the upgrade.
If the source control plane holds more than one organization, the dashboard remains unavailable after the upgrade until an owner keeps one organization and permanently deletes every other one. Back up the database and verify the organization inventory before starting.
From 1.6.x or Earlier: Replace Retired SSRF Settings
The target control plane uses one server-side request forgery (SSRF) policy for all outbound calls to user-supplied URLs. Replace any retired per-connection setting before upgrading:
| Removed Helm value | Removed variable | Removed configuration key |
|---|---|---|
api.playgroundAllowPrivateIPs | AISIX_PLAYGROUND_ALLOW_PRIVATE_IPS | outbound.playground_allow_private_ips |
api.notifyAllowPrivateURLs | AISIX_CLOUD_NOTIFY_ALLOW_PRIVATE_URLS | outbound.notify_allow_private_urls |
api.mcpSpecAllowPrivateURLs | AISIX_CLOUD_MCP_SPEC_ALLOW_PRIVATE_URLS | outbound.mcp_spec_allow_private_urls |
api.guardrailTestConnectionAllowInsecure | AISIX_GUARDRAIL_TEST_CONNECTION_ALLOW_INSECURE | outbound.guardrail_test_connection_allow_insecure |
Configure the replacement in the same layer that owns the rest of your control-plane settings:
| Configuration method | Replacement settings |
|---|---|
| Helm | api.outbound.ssrfProtection.enabled and api.outbound.ssrfProtection.allowedHosts |
| Environment | AISIX_CLOUD_SSRF_PROTECTION_ENABLED and AISIX_CLOUD_SSRF_PROTECTION_ALLOWED_HOSTS |
| Configuration file | outbound.ssrf_protection.enabled and outbound.ssrf_protection.allowed_hosts |
Retired settings are ignored after the upgrade. A Helm release upgraded from chart 1.5.0 with helm upgrade --reuse-values still carries that chart's false defaults for api.playgroundAllowPrivateIPs and api.notifyAllowPrivateURLs, but those values are no longer read. On-premises SSRF protection stays off unless you enable the replacement, so the playground and budget notifications can then reach private destinations. If a retired setting was false to refuse private destinations, enable the replacement policy and allow only the internal hosts that must remain reachable. See Private Network Access.
From 1.7.0 or Earlier: Prepare the Database
AISIX Enterprise now connects through one database URL and no longer uses PostgreSQL Row-Level Security.
| Change | Required action |
|---|---|
| One database connection | Set database.url to the database owner's connection and remove database.admin_url. For Helm, disable twoDSN.enabled. |
| Database ownership | Confirm that the connection role owns the control-plane database and tables. |
| Legacy role attributes | Keep CREATEROLE and BYPASSRLS while rollback remains possible. Remove them after the rollback window closes. |
| Tables owned by another role | Arrange for the owner or a database administrator to remove the old RLS settings if startup reports an ownership error. See Tables Owned by Another Role. |
Helm Releases First Installed with Chart 1.5.0
Charts 1.6.x and 1.7.x kept two things for a release first installed with chart 1.5.0, which ran the dashboard as a separate workload. The target chart removes both. Before upgrading such a release:
| Existing configuration | Required action |
|---|---|
AISIX_TRUSTED_ORIGINS or AISIX_AUTH_BEARER_SESSIONS in ui.extraEnvVars | Move it to api.trustedOrigins or api.bearerSessions, or to api.extraEnvVars. The target chart no longer passes ui.extraEnvVars to the control-plane API, so an entry left there stops taking effect. |
A NodePort, ingress, or reverse proxy that uses the <release>-ui Service | Point it at the <release>-api Service, which serves the dashboard on every path. The target chart removes the <release>-ui Service and its ui.service values. |
Also check for environment variables listed twice, as described in Review Control-Plane Values.
Upgrade a Package Installation
Online and air-gapped packages follow the same upgrade model: replace the package files in the existing installation directory, then run the updated startup script. The package preserves the deployment's environment file and PostgreSQL data volume.
Back Up the Installation
Create a complete recovery set before replacing any files. The first control-plane start under the target release migrates the database, so rollback requires the matching database backup, secrets, configuration, and previous package.
Upgrade an Online Installation
From the directory that contains aisix-self-hosted, run the quickstart again. It downloads the current package, extracts it over the existing installation, and starts the upgrade:
curl -sL "https://run.api7.ai/aisix-self-hosted/quickstart" | bash
Upgrade an Air-Gapped Installation
On a connected machine, download the package for the air-gapped host's CPU architecture. This URL is pinned to this release.
curl -fSL "https://run.api7.ai/aisix-self-hosted/aisix-self-hosted-offline-1.9.0-linux-amd64.tar.gz" \
-o aisix-self-hosted-offline-1.9.0-linux-amd64.tar.gz
Replace amd64 with arm64 for an AArch64 host. The legacy URL without an architecture suffix still resolves to the AMD64 package. The startup script refuses a mismatched package before loading any image and prints the correct download URL.
Transfer the archive to the target host and extract it from the directory that contains the installation:
cd /path/that/contains/aisix-self-hosted
tar -xzf aisix-self-hosted-offline-1.9.0-linux-amd64.tar.gz
cd aisix-self-hosted
./run.sh
Extract the package over the original installation directory. Extracting it from inside that directory creates a nested copy and does not upgrade the running installation. Extracting into a different directory leaves the new copy without the original environment file, and the startup script refuses to take over a stack running elsewhere.
Verify the Package Upgrade
For a normal release-to-release upgrade, the package updates AISIX_VERSION in .env to the packaged release. A non-release value is treated as an operator-owned custom pin and is preserved. The package does not change deployment secrets or replace the data volume. Confirm the running images after the script finishes:
COMPOSE_PROJECT_NAME=aisix-self-hosted docker compose images
Three optional image overrides take precedence over the package version: AISIX_API_IMAGE, AISIX_DPM_IMAGE, and AISIX_CLOUD_DP_IMAGE. Remove an override before upgrading if that component should follow the package. See AISIX Enterprise Configuration.
On an air-gapped host, image archives from the previous package remain available until the new release starts successfully. This preserves the images needed for rollback if startup fails.
Upgrade with Helm
The control-plane and gateway charts use the same release number. Upgrade and verify the control plane before changing any gateway release.
Prepare the Helm Upgrade
Install Helm 3.15 or a later Helm 3 release, cURL, and jq. Plan a control-plane maintenance window, and create a complete recovery set whether the database is bundled or external. Verify that the database backup in the set can be restored before continuing.
The examples use aisix-cp as the control-plane release name and aisix as its namespace, matching Deploy the AISIX Enterprise Control Plane. If your deployment uses different names, find them with helm list -A and substitute them throughout the procedure.
Set the control-plane release, namespace, target version, and timeout:
export CP_NAMESPACE="aisix"
export CP_RELEASE="aisix-cp"
export TARGET_VERSION="1.9.0"
export CP_UPGRADE_TIMEOUT="35m"
The timeout exceeds the chart's default control-plane startup budget. Increase it if database migrations can take longer.
Record the installed control-plane chart and application versions before making changes:
helm list --namespace "$CP_NAMESPACE"
kubectl get pods --namespace "$CP_NAMESPACE"
Refresh the chart repository and confirm that the target chart is available:
helm repo add api7 https://charts.api7.ai
helm repo update
helm show chart api7/aisix-cp --version "$TARGET_VERSION"
Use a maintained values file rather than --reuse-values. Reusing the resolved values from the source chart can prevent target-chart defaults, including probe budgets, from taking effect.
Point the examples at the values file maintained for the release:
export CP_VALUES_FILE="your-cp-values.yaml"
If you do not have a maintained file, export only the user-supplied values with restrictive permissions:
export CP_VALUES_FILE="cp-values.yaml"
umask 077
touch "$CP_VALUES_FILE"
chmod 600 "$CP_VALUES_FILE"
helm get values "$CP_RELEASE" \
--namespace "$CP_NAMESPACE" \
-o yaml > "$CP_VALUES_FILE"
Do not export computed defaults with helm get values --all. Treat the values file as sensitive because it can contain credentials.
Review Control-Plane Values
Configure application settings through chart values. Reserve extraEnvVars for system-level variables such as TZ; secrets remain in Kubernetes Secrets.
An application setting supplied through extraEnvVars still overrides the rendered configuration file after the upgrade. Move each setting to its chart value, then remove the environment-variable override so the values file remains the source of truth.
| Environment-variable override | Chart value |
|---|---|
AISIX_TRUSTED_ORIGINS | api.trustedOrigins |
AISIX_CLOUD_SSRF_PROTECTION_ENABLED | api.outbound.ssrfProtection.enabled |
See Helm Values for the complete mapping.
Find Variables Listed Twice
Charts 1.6.x and 1.7.x keep the entry that chart 1.5.0 rendered for a variable ahead of an api.extraEnvVars or dpm.extraEnvVars override of the same name, so the Deployment lists that variable twice. The target chart lists such a variable once, and Helm's three-way merge then removes both entries: the first helm upgrade to the target drops the variable from the Deployment. List the variables that appear twice in either Deployment before upgrading:
for component in api dpm; do
kubectl get deployment -n "$CP_NAMESPACE" \
-l "app.kubernetes.io/instance=$CP_RELEASE,app.kubernetes.io/component=$component" \
-o json \
| jq -r --arg component "$component" \
'.items[0].spec.template.spec.containers[0].env // []
| group_by(.name) | map(select(length > 1) | .[0].name)
| .[] | "\($component): \(.)"'
done
No output means the upgrade drops nothing. For each listed variable, move the setting to its key in values.yaml and remove the extraEnvVars entry before you upgrade, not afterwards. This matters most for a database URL: once the override is dropped, cp-api starts, and runs its migrations, against the database the chart derives from values.yaml. Render the upgrade and confirm that the database it names is the one you mean before continuing.
A moved variable that the target chart writes into the configuration file, such as AISIX_CLOUD_PUBLIC_BASE_URL or AISIX_CLOUD_DATABASE_URL, then leaves the Deployment as intended, and the component reads the value from the configuration file. A moved variable that the target chart still sets as an environment variable itself, such as AISIX_CLOUD_MASTER_KEY, AISIX_DPMGR_MASTER_KEY, or PGPASSWORD, keeps the chart's own entry through the upgrade. Once every listed setting is moved, a single upgrade is enough.
Check Image Pins
Check whether the installed release pins either control-plane image:
helm get values "$CP_RELEASE" \
--namespace "$CP_NAMESPACE" \
-o json \
| jq '{api_image_tag: (.api.image.tag // ""), dpm_image_tag: (.dpm.image.tag // ""), generated_gateway_image: (.api.dpImage // "")}'
Review each returned value:
| Value | Action |
|---|---|
| API or data-plane manager image tag | An empty tag follows the target chart. Remove an old pin or update it to a target-compatible image. |
| Generated gateway image | This image appears in dashboard-generated installation commands. Clear or update an old pin; preserve only a deliberate target-compatible custom image. |
Render the Upgrade
Resolve the control-plane API Deployment name from the Helm release label:
export CP_API_DEPLOYMENT="$(kubectl get deployment -n "$CP_NAMESPACE" \
-l "app.kubernetes.io/instance=$CP_RELEASE,app.kubernetes.io/component=api" \
-o jsonpath='{.items[0].metadata.name}')"
printf 'Control-plane API: %s\n' "$CP_API_DEPLOYMENT"
Stop and verify the release name, namespace, and Kubernetes context if the value is empty.
Render the upgrade against the live cluster before changing the release. --dry-run=server permits cluster lookups and OpenAPI validation, while --hide-secret prevents Helm from printing rendered Secrets to the terminal or CI log:
helm upgrade "$CP_RELEASE" api7/aisix-cp \
--namespace "$CP_NAMESPACE" \
--version "$TARGET_VERSION" \
--values "$CP_VALUES_FILE" \
--dry-run=server \
--hide-secret
This command does not submit the rendered objects to Kubernetes admission. Treat it as a rendering and OpenAPI check, not as validation of SCCs, quotas, or admission policies. Resolve every reported error before continuing.
Inspect every image in the target control-plane render:
helm template "$CP_RELEASE" api7/aisix-cp \
--namespace "$CP_NAMESPACE" \
--version "$TARGET_VERSION" \
--values "$CP_VALUES_FILE" \
| grep -E '^[[:space:]]+image:'
The aisix-cp-api and aisix-cp-dpm images should use the target version or a deliberate target-compatible custom tag. PostgreSQL is an independently versioned chart dependency. Keep the PostgreSQL image tag rendered by the target chart unless a separately tested database-image plan requires another tag.
Upgrade the Control Plane
Upgrade without --atomic. The control-plane API migrates the database during startup, while an automatic Helm rollback changes only Kubernetes objects and does not restore the complete recovery set.
helm upgrade "$CP_RELEASE" api7/aisix-cp \
--namespace "$CP_NAMESPACE" \
--version "$TARGET_VERSION" \
--values "$CP_VALUES_FILE" \
--wait \
--timeout "$CP_UPGRADE_TIMEOUT"
If an upgrade already dropped a variable you had not moved, run helm upgrade again with the same values to restore it. Then move the setting to its chart value. A ready cp-api is no evidence that the first upgrade went well. A dropped AISIX_CLOUD_MASTER_KEY does show: cp-api exits at startup with master key is not set: set AISIX_CLOUD_MASTER_KEY to the base64-encoded 32-byte key dp-manager has in AISIX_DPMGR_MASTER_KEY and restarts repeatedly, so its pod never becomes ready. It keeps restarting until the second upgrade restores the original key.
Watch the rollout. If the API pod does not become ready, describe the non-ready pod first and read its logs if the container started:
kubectl rollout status -n "$CP_NAMESPACE" \
"deployment/$CP_API_DEPLOYMENT" \
--timeout="$CP_UPGRADE_TIMEOUT"
kubectl get pods -n "$CP_NAMESPACE" \
-l "app.kubernetes.io/instance=$CP_RELEASE,app.kubernetes.io/component=api"
kubectl describe pod -n "$CP_NAMESPACE" <non-ready-cp-api-pod>
kubectl logs -n "$CP_NAMESPACE" \
<non-ready-cp-api-pod> \
--all-containers \
--tail=300
A failed database migration, an unreachable database, or a missing Secret can prevent the API from becoming ready. Do not repeatedly rerun the upgrade for those failures. If the migration cannot complete, follow Roll Back to restore the complete pre-upgrade recovery set. If a variable that the values still set is missing from the Deployment, run the upgrade command again with the same values to put it back.
The data-plane manager can briefly log missing-table errors while the API applies database migrations. It retries automatically. Investigate the errors if they continue after the API becomes ready.
Verify the Control Plane
Verify the control-plane version through its public endpoint. Set AISIX_CP to the existing AISIX Cloud Admin API base URL, including /api and without a trailing slash:
export AISIX_CP="YOUR_AISIX_CONTROL_PLANE_API_URL"
curl -fsS "$AISIX_CP/config/public" | jq '{cp_version, cp_commit}'
Sign in to the dashboard and confirm that organizations, environments, models, provider keys, and caller API keys are present. In each environment's Data planes view, confirm that the existing gateways remain healthy.
Monitor Database Work
The control-plane API applies schema migrations before it becomes ready. Some releases also build indexes after the API starts serving, so the dashboard and gateway configuration delivery can become available before all database work finishes.
Watch the control-plane API logs for these messages:
| Log message | Meaning |
|---|---|
building index or index build progress | A background index is being built. Duration and database load depend on table size and infrastructure. |
index built | One index has completed. |
background index build: every index is in place | All background indexes are ready. Wait for this message before starting another upgrade. |
While required indexes are being built, request records continue to be stored, but budget accounting and some cleanup jobs wait. Until the usage index is ready, the Overview and Usage pages show zero, including traffic received after the upgrade, together with a backfill notice. After that index is ready, those pages fill in earlier usage in the background and stay incomplete until the notice disappears. See Backfill after an Upgrade.
Plan an off-peak window for a deployment with large usage tables because index creation increases database CPU, I/O, and write-ahead logging.
Package Upgrade Progress
The package startup script brings PostgreSQL, the control-plane API, the data-plane manager, and the remaining services up in order. When a stage takes longer than expected, it prints progress every 30 seconds:
| Message | Action |
|---|---|
cp-api is still migrating the database | Leave the migration running. If the message identifies a table lock, inspect the API logs for the blocking session. |
cp-api is still starting | Continue waiting for the first startup to finish. |
PostgreSQL is recovering from an unclean shutdown | Wait for PostgreSQL readiness as described below. |
Pressing Ctrl-C does not stop a database migration already running in the container, but the startup script is still needed to start later services. Run it again after the migration completes. Use ./run.sh logs api to follow migration and index progress.
Table Locks Held by Another Session
Migration work retries rather than waiting indefinitely behind a table lock. The control-plane API log identifies the blocking session, including its process ID, application name, transaction start time, and query. Let that transaction finish or end it; also confirm that no control-plane replica from the previous release is still using the database.
Tables Owned by Another Role
This section applies to a database created by 1.7.0 or earlier. At startup, the control-plane API removes the RLS settings that the earlier release installed. If a table carrying those settings belongs to another role, startup stops without changing any table.
Ask the table owner or a database administrator to run the statements named in the startup error for every affected table:
ALTER TABLE public."<table>" NO FORCE ROW LEVEL SECURITY;
ALTER TABLE public."<table>" DISABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS tenant_isolation ON public."<table>";
Start the control plane again after correcting every affected table.
PostgreSQL Recovery After an Interrupted Stop
./run.sh stop and ./run.sh down give each container up to 2 minutes to shut down, because PostgreSQL's shutdown checkpoint can take longer than the 10-second Docker Compose default after heavy writes. A stop made with the previous package's run.sh still uses 10 seconds.
If PostgreSQL was interrupted, it replays its write-ahead log before accepting connections. The startup script waits up to 30 minutes and reports recovery progress. If recovery takes longer, wait until ./run.sh logs postgres shows database system is ready to accept connections, then run ./run.sh again.
Complete Required Post-Upgrade Actions
Complete any action that blocks normal control-plane use before upgrading the gateway fleet.
Consolidate Several Organizations into One
This section applies to a control plane upgraded from 1.5.x or earlier that still holds several organizations. Until only one remains, users cannot access the dashboard; admin tokens and gateway traffic continue to work.
Consolidation permanently deletes every organization except the one you keep, including organizations you do not belong to. Environments, models, caller API keys, members, and usage and audit records are deleted with them. Certificates for gateways connected to deleted environments are revoked. There is no undo. Restore the database backup if you need to recover the deleted data.
An owner of at least one organization can consolidate after signing in with a password:
- Open the Keep one organization page.
- Choose the organization to retain. Only organizations you own are offered.
- Review every organization that will be deleted.
- Type the retained organization's slug, shown in parentheses beside its name, then select Delete.
When one organization remains, the dashboard opens it and records the consolidation in its audit log. Accounts with passwords remain, but nobody is added to the retained organization automatically. An account without a password is deleted when it belonged only to deleted organizations. Invite retained users who no longer belong to an organization. If consolidation stops part-way, run it again to remove the remaining organizations.
Verify password sign-in and invitation flows before continuing.
Upgrade the Gateways
Review each gateway release's values before starting its rollout:
| Existing configuration | Action |
|---|---|
Application settings in extraEnvVars | Move them to config, configSecrets, or rateLimit.redis. For example, move AISIX_OBSERVABILITY__LOG_LEVEL to config.observability.log_level. |
AISIX_CONFIG_PATH override | Leave it in place for the version upgrade. Remove it after verification by following the gateway cleanup procedure. |
AISIX_RATELIMIT__REDIS__URL override | Leave it in place only when rateLimit.backend is redis and either rateLimit.redis.url or rateLimit.redis.existingSecret is configured. Remove it after verification. |
The chart refuses configuration keys that it owns directly, such as listener addresses and the control-plane connection. Store Redis credentials in a Secret rather than under config. See Set Any Other Gateway Configuration.
After the control plane passes verification, follow Upgrade a Gateway on Kubernetes for every gateway release. Use the same target version as the control-plane chart. The first upgrade that renders the gateway configuration file replaces every gateway pod, even when the settings themselves are unchanged.
Keep the complete recovery set until the control plane and every gateway have operated normally through the observation period defined by your change policy.
Roll Back
Roll back in the reverse order: gateways first, then the control plane.
A control-plane rollback restores the complete pre-upgrade recovery set, not only the images. The target release has already migrated the database, so restore the matching database, secrets and master keys, deployment configuration, and previous software version together.
For a package installation, restore the recovery set and previous package, then acknowledge the intentional downgrade:
AISIX_ALLOW_DOWNGRADE=1 ./run.sh
Confirm that the startup output reports the version you intended to restore.
For a Helm installation, restore the complete recovery set before using helm rollback to return the workloads to the previous revision.
Clean Up After the Rollback Window
Complete only the cleanup that applies to the release you upgraded from. For a deployment upgraded from 1.5.x or earlier, remove the obsolete dashboard image and workload settings from image mirrors, allow-lists, values files, and .env.
Remove CREATEROLE and BYPASSRLS
After the rollback window closes, the database connection role no longer needs CREATEROLE or BYPASSRLS:
ALTER ROLE aisix NOCREATEROLE NOBYPASSRLS;
Replace aisix with the configured connection role. A rollback to 1.7.0 or earlier needs both attributes again.
Remove the cp_api_app Role
The control plane no longer uses cp_api_app but does not drop it, because another control-plane database on the same PostgreSQL cluster may still use it. Once no database needs the role, run the following in every database where it has grants:
REASSIGN OWNED BY cp_api_app TO aisix;
DROP OWNED BY cp_api_app;
Replace aisix with that database's owner. Then drop the role once:
DROP ROLE cp_api_app;
DROP ROLE needs a superuser or a role with CREATEROLE; on PostgreSQL 16 and later, that role also needs ADMIN OPTION on cp_api_app.
AISIX Enterprise Situations That Are Not Supported
- Adding a gateway older than the environment's existing configuration already requires. The mixed-version window covers gateways moving forward. Do not add an older gateway to an environment whose saved configuration already depends on a newer release; that gateway would not load the configuration.
- Upgrading gateways before the AISIX Enterprise control plane. Upgrade the control plane before its connected gateways.
- Connecting a gateway older than 1.6.0. The control plane does not check saved configuration against such a gateway, and the gateway may fail to load it. Upgrade it to 1.6.0 or later.
- Upgrading a control plane older than 1.6.0 directly to this release. Upgrade it to 1.6.x or 1.7.x first. See Plan the Upgrade.