> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bytebase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bytebase 3.21.0 - Jul 30, 2026

> Label-driven Approvals and MySQL State-based GitOps

## 🔔 Notable Changes

* **Label-driven approvals and draft-time issue labels** — Previously, issue labels could only be added at the Ready for Review step or after a plan was already in review — a real bottleneck for workspaces that require labels on issues. You can now add issue labels while drafting the plan, and Custom Approval conditions can reference them, opening up label-based routing of reviews (e.g., an `incident-mode` label selecting an incident approval path).

* **MySQL state-based GitOps workflow (beta)** — Declarative (SDL) schema management now covers MySQL, in beta alongside PostgreSQL: declare the target schema, and Bytebase computes and applies the migration — covering routines, triggers, and events. See [docs](/gitops/state-based-workflow/overview).

* **API breaking changes** — Several API methods moved to new services or were removed; REST paths are mostly unchanged and legacy request formats are converted transparently. gRPC/Connect callers and OpenAPI-generated SDKs should review before upgrading. See [change details](#api-breaking-changes).

## 🚀 Features

* **SQL Editor** — Query histories and worksheets can now be listed across users and projects through new List APIs — for admins and integrations that need more than their own items — while the Search APIs stay scoped to the calling user (query histories: new `bb.queryHistories.list` permission, granted to workspace admins and project owners; worksheets: new `bb.worksheets.list` permission, not granted to any predefined role).

* **Bytebase Cloud** — A new step-by-step setup guide walks new workspaces from creating a project through connecting an instance to running the first query.

* **Self-hosted (Helm)** — Pin the Bytebase container image by digest.

## 🎄 Enhancements

* Smoother first-run setup: when the workspace has no instance yet, you can create an instance directly from an empty project, and the databases found on that instance's first sync are assigned to that project. Connection failures now explain what went wrong.

* **SQL review** — The maximum SQL file size is now a configurable built-in rule: set the level (warning/error) and the size limit (default 2MB).

* **Plan detail** — Navigation is steadier: switching between changes, stages, and tasks preserves page context and works with browser history, and each change is labeled by its target databases rather than a generic label.

* List pages keep your filters and scroll position across browser navigation, including paginated dashboards.

* **SQL Editor** — Search within a result's detail view, and code assistance reconnects automatically after a disconnect.

* **GitOps** — Active VCS user tracking now covers Azure DevOps pull-request authors.

* **SQL parsing** — Broader SQL compatibility across PostgreSQL, Oracle, SQL Server, and Trino — notably, modern `pg_dump`/`pg_dumpall` scripts with psql meta-commands and inline `COPY` data now work in change workflows.

* **PostgreSQL** — Schema sync, SDL dump, and Sync Schema now support composite types (`CREATE TYPE … AS`).

* **Oracle** — Prior backup now deduplicates rows by `ROWID`, enabling multi-statement backups on tables with `CLOB`/`BLOB`/`NCLOB` columns; tables with unsupported `LONG`/`LONG RAW` columns are flagged before execution.

## 🐞 Bug Fixes

* Skipped rollout tasks are now terminal — they no longer reappear as actionable or can be run after being skipped.

* Fix sign-in and navigation traps: SSO logins no longer ask for a local password reset, the project selector no longer lands on a permission-denied page, and the SQL Editor no longer loops on a 403 after a session change.

* Webhook fixes: Discord notifications are no longer delivered three times, and `PIPELINE_COMPLETED` now reports the completed stage's environment instead of always the first stage's.

* Fix assorted UI issues: CosmosDB container selection loss after running a query, SQL Editor result-panel display, and disabled batch-action tooltips.

* **Oracle** — Fix schema sync failing on malformed non-UTF-8 metadata in any schema object (extends the 3.20.1 view fix), and fix PL/SQL package bodies with block comments being split incorrectly, which sent trailing SQL\*Plus `/` delimiters to the database.

## 🏗️ Terraform

* Upgrade to provider **3.21.0** after upgrading the server — [Migration Guide](https://github.com/bytebase/terraform-provider-bytebase/blob/main/migration/3.21.0.md). **Optional:** Spanner and BigQuery data sources take explicit `project_id`/`instance_id` (legacy `host` values keep working and convert automatically), and Vault external secrets support TLS configuration (`vault_ssl_ca`, `vault_ssl_cert`, `vault_ssl_key`, `skip_vault_tls_verification`).

## 📃 Change Details

### API Breaking Changes

**1. Spanner and BigQuery data sources: `host` replaced by `project_id` / `instance_id`**

The GCP resource identity moves out of the overloaded `host` field into dedicated `DataSource.project_id` / `instance_id` fields; `host` and `port` are now an optional Google API endpoint override (e.g. a Private Service Connect endpoint like `spanner-nonprod.p.googleapis.com`).

| Engine   | Before                                     | After                                           |
| -------- | ------------------------------------------ | ----------------------------------------------- |
| Spanner  | `host: "projects/<proj>/instances/<inst>"` | `project_id: "<proj>"`, `instance_id: "<inst>"` |
| BigQuery | `host: "<proj>"`                           | `project_id: "<proj>"`                          |

Affected routes: consumers of `InstanceService.GetInstance` / `ListInstances` that parse `host` — read `project_id` / `instance_id` instead. Writes in the legacy format are transparently converted, so existing API callers and Terraform configs keep working; `UpdateDataSource` accepts `project_id` / `instance_id` in `update_mask`. Existing data sources are migrated automatically on upgrade.

**2. `SearchQueryHistories` moved to a project-scoped route, `parent` required**

|                                      | Before                           | After                                                |
| ------------------------------------ | -------------------------------- | ---------------------------------------------------- |
| REST                                 | `POST /v1/queryHistories:search` | `POST /v1/{parent=projects/*}/queryHistories:search` |
| `SearchQueryHistoriesRequest.parent` | absent (searched all projects)   | required; `projects/{project}`                       |

Affected routes: callers of the old path get 404; Connect/gRPC callers omitting `parent` get `InvalidArgument`. The CEL `project ==` filter still works and composes with `parent`.

**3. Changelog APIs moved to `ChangelogService`**

`ListChangelogs` and `GetChangelog` moved from `DatabaseService` to the new `ChangelogService`. The old gRPC/Connect method names are removed; REST paths, permissions, and payloads are unchanged.

| Method                | Before                                            | After                                              |
| --------------------- | ------------------------------------------------- | -------------------------------------------------- |
| List / get changelogs | `DatabaseService.ListChangelogs` / `GetChangelog` | `ChangelogService.ListChangelogs` / `GetChangelog` |

Affected routes: gRPC/Connect callers of the old method names, and OpenAPI-generated SDKs (operationIds are now `ChangelogService_*`). REST callers need no changes.

**4. Query history APIs moved to `QueryHistoryService` (deprecation)**

`SearchQueryHistories` and `GetQueryHistory` moved from `SQLService` to the new `QueryHistoryService`, which also hosts the new `ListQueryHistories` List API. The old `SQLService` method names keep working as deprecated aliases and will be removed in a future release. Permissions and payloads are unchanged; REST paths are unchanged except `SearchQueryHistories`, whose route moved — see item 2.

| Method        | Before (deprecated)                                   | After                                                          |
| ------------- | ----------------------------------------------------- | -------------------------------------------------------------- |
| Query history | `SQLService.SearchQueryHistories` / `GetQueryHistory` | `QueryHistoryService.SearchQueryHistories` / `GetQueryHistory` |

Affected routes: migrate gRPC/Connect callers before the aliases are removed; OpenAPI operationIds are now `QueryHistoryService_*`. REST callers need no changes.

**5. `SQLService.DiffMetadata` replaced by `DatabaseService.DiffMetadata`**

The anonymous `SQLService.DiffMetadata` and its REST path are removed. `DatabaseService.DiffMetadata` reads the source schema from the database resource — send only the database `name` and the complete `target_metadata` — and requires the new `bb.databases.diffMetadata` permission (granted to workspace admin/DBA and project owner/developer; add it to custom roles as needed).

|         | Before                                         | After                                                          |
| ------- | ---------------------------------------------- | -------------------------------------------------------------- |
| Method  | `SQLService.DiffMetadata`                      | `DatabaseService.DiffMetadata`                                 |
| REST    | `POST /v1/schemaDesign:diffMetadata`           | `POST /v1/{name=instances/*/databases/*}:diffMetadata`         |
| Request | `source_metadata`, `target_metadata`, `engine` | `name`, `target_metadata` (source and engine read server-side) |
| Auth    | None (anonymous)                               | IAM, `bb.databases.diffMetadata`                               |

Affected routes: any caller of the old method or REST path; update the request shape and grant the permission.

**6. `SQLService.AICompletion` removed — use `AIService.Chat`**

|        | Before                    | After            |
| ------ | ------------------------- | ---------------- |
| Method | `SQLService.AICompletion` | `AIService.Chat` |

Affected routes: any caller of `AICompletion`; the chat request is a superset of the old request. This also fixes AI dynamic suggestions failing on workspaces using the Claude provider.

**7. `SQLITE` removed from the `Engine` enum (cleanup)**

The console has not offered SQLite for years; this removes the leftover enum value and driver. Remove any remaining `SQLITE` references (API callers or Terraform `engine` values).

**8. `Instance.sync_databases` reshaped**

| Field                     | Before                               | After                                                                                                      |
| ------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| `Instance.sync_databases` | `repeated string` (empty = sync all) | `SyncDatabases` message (unset = sync all; set with an explicit list = sync exactly those, including none) |

Affected routes: `InstanceService.CreateInstance` / `UpdateInstance` callers using this field. This also fixes selecting *zero* databases to sync — previously an empty selection synced everything.

**9. `has_issue` Plan list filter removed**

Affected routes: `PlanService.ListPlans` / `SearchPlans` callers still sending `has_issue` receive `InvalidArgument`.

## ⚙️ Install and Upgrade

* [Fresh install](/get-started/self-host/deploy-with-docker)

* [Upgrade](/get-started/self-host/upgrade)

*Before upgrading: 1) Back up the [metadata](https://www.bytebase.com/docs/administration/back-up-restore-metadata/) — in-place downgrade is not supported. 2) Do not run multiple containers on the same data directory. 3) Terraform users: upgrade Bytebase server first, then apply the new Terraform config.*
