Create, read, update, delete, and manage databases.
Common Commands
# List all databases
pscale database list --org <org>
# Create database
pscale database create <database> --org <org>
pscale database create <database> --org <org> --engine neki --region <region> --cluster-size <size> --replicas <count> --min-storage <bytes> --max-storage <bytes> --wait --format json
# Show database details
pscale database show <database> --format json
# Inspect database-level defaults for future Vitess deploy requests
pscale database throttler show <database> --org <org> --format json
Inspect database-level aggressive cutover for future Vitess deploy requests
pscale database aggressive-cutover show --org --format json
Update one setting; boolean flags require an explicit valuepscale database update --require-approval-for-deploy=true
Inspect PostgreSQL IP restrictionspscale database ip-restriction list --format json
Discover valid branch/read-only region targets for a databasepscale database regions list --org --format json pscale database read-only-regions list --org --format json
Delete databasepscale database delete
Delete a Vitess keyspace (destructive; inspect and approve first)pscale keyspace delete
Inspect a Vitess keyspace's throttler, durability, and VReplication settingspscale keyspace settings --format json
Compatibility-check an existing MySQL source before creating an external keyspace SOURCE_PASSWORD must be injected into this same trusted shell invocation.pscale keyspace create-external
--org --host --source-database
--username --password "${SOURCE_PASSWORD:?source password not set}"
--ssl-mode verify_identity --dry-run --format json
pscale shell pscale shell --db-name pscale shell --router
List configured Vitess read-only regions for a keyspacepscale keyspace read-only-regions --format json
Add or resize a Vitess read-only regionpscale keyspace read-only-regions add
--cluster-size --replicas
pscale keyspace read-only-regions update
--cluster-size --replicas
pscale database dump
--keyspace
--read-only-region
--output ./dump
## Workflows
### Database Creation
```bash
# Create new database
pscale database create my-new-db --org my-org
# Create a Neki database after confirming region, size, replicas, storage bounds, and cost
pscale size cluster list --org my-org --engine neki --format json
pscale database create my-new-neki-db --org my-org \
--engine neki \
--region <region> \
--cluster-size <size> \
--replicas <count> \
--min-storage <bytes> \
--max-storage <bytes> \
--wait \
--format json
# Create main branch (automatic)
# Create development branch
pscale branch create my-new-db development
Use pscale size cluster list --engine neki for valid Neki sizes. The --region, --min-storage, and --max-storage flags are Neki creation inputs; storage bounds are byte counts. The help documents --replicas 0 for single-node Postgres, not Neki, so confirm supported Neki replica counts before creating and use 2 or more for HA. Neki-specific topology, shard, profile, router, sidecar, admin, and restore workflows belong in pscale-neki; keep this skill to database-level creation and discovery.
Database Shell Access
# Open shell to specific branch
pscale shell my-database main
# PostgreSQL only: select the logical database explicitly
pscale shell my-database main --db-name app_db
# Equivalent positional form
pscale shell my-database main app_db
# Neki only: connect through a named router
pscale shell my-database main --router router-a
# Agent-friendly, non-interactive query path
pscale sql my-database main --org my-org --format json \
--dbname app_db --query "SELECT 1"
--db-name and the third positional argument are mutually exclusive and only supported for PostgreSQL; omitting both connects to postgres. Vitess/MySQL shells reject either form. Neki shells can use --router to connect through a named router. PostgreSQL and Neki shell access requires an interactive terminal and a locally installed psql client. Without a TTY, or when output format is not human, pscale shell fails unless PSCALE_ALLOW_NONINTERACTIVE_SHELL is set; do not use that bypass for ordinary automation. Use pscale sql <database> <branch> --org <org> --format json --query '<sql>' instead. Its PostgreSQL/Neki logical-database flag is spelled --dbname (no hyphen), not shell's --db-name.
Database settings
Inspect the complete current settings before changing anything, then pass only the intended update flags. Boolean flags must use =true or =false; merely naming a boolean flag is not a safe way to express operator intent.
pscale database show <database> --org <org> --format json
# Cross-engine examples
pscale database update <database> --org <org> --new-name <new-name>
pscale database update <database> --org <org> --restrict-branch-region=true
# Vitess-only examples
pscale database update <database> --org <org> --require-approval-for-deploy=true
pscale database update <database> --org <org> --insights-raw-queries=false
The CLI rejects Vitess-only flags for PostgreSQL databases. --default-branch, --new-name, --production-branch-web-console, and --restrict-branch-region work for both engines. Renaming or changing a default branch can affect automation and connection workflows; confirm the database and proposed diff before executing, then re-run database show to verify.
Database-level Vitess migration throttler
This configuration sets the default migration-throttling ratio for future deploy requests on a Vitess database. It is distinct from both pscale deploy-request throttler for one deploy request and pscale branch vtctld throttler for tablet/keyspace throttler policy.
# Inspect current database defaults and eligible keyspaces
pscale database throttler show <database> --org <org> --format json
# Apply one ratio to all eligible keyspaces after explicit approval
pscale database throttler update <database> --org <org> \
--ratio 25 \
--format json
# Or set reviewed per-keyspace ratios; the flag is repeatable
pscale database throttler update <database> --org <org> \
--configuration commerce=20 \
--configuration analytics=10 \
--format json
# Verify the resulting defaults
pscale database throttler show <database> --org <org> --format json
Pass exactly one update mode: --ratio or one or more --configuration keyspace=ratio values. Ratios range from 0 through 95; 0 effectively disables migration throttling, while 95 slows migrations the most. Because a change affects future schema deployment behavior, show the current configuration and complete proposed values, obtain explicit approval, then verify the returned and re-read configuration. The command rejects PostgreSQL databases.
Database-level Vitess aggressive cutover
Aggressive cutover is a Vitess database setting for future deploy requests. When enabled, those deploy requests cut over more aggressively while waiting on table locks. It is not the same action as pscale deploy-request force-cutover, which affects one already-running deployment.
# Read current state
pscale database aggressive-cutover show <database> --org <org> --format json
# After reviewing lock/transaction impact and obtaining explicit approval
pscale database aggressive-cutover enable <database> --org <org> --format json
# or
pscale database aggressive-cutover disable <database> --org <org> --format json
# Verify persisted state
pscale database aggressive-cutover show <database> --org <org> --format json
The command rejects PostgreSQL databases. Enabling it can shorten cutover waits but may increase the chance that blocking application transactions are interrupted. Confirm the database, current setting, expected migration workload, application tolerance, and rollback choice before changing it. JSON output exposes the resulting enabled boolean; verify that field after the write.
PostgreSQL IP restrictions
IP restrictions apply at the database level across all branches. List and inspect existing entries first, use IPv4 CIDRs (a single address is /32), and omit --schema or --role to apply the rule to all schemas or roles.
pscale database ip-restriction list <database> --org <org> --format json
pscale database ip-restriction create <database> --org <org> \
--cidrs 203.0.113.10/32,198.51.100.0/24 \
--schema public --role app_reader \
--description "approved application networks"
pscale database ip-restriction show <database> <entry-id> --org <org> --format json
pscale database ip-restriction update <database> <entry-id> --org <org> \
--cidrs 203.0.113.10/32
On update, only supplied flags change; an empty description clears it, while empty schema/role broadens the entry to all schemas/roles. Before delete, verify the entry ID and replacement access path, obtain approval, avoid --force unless explicitly authorized, and list the rules again afterward. Removing or narrowing the wrong rule can block database access; broadening one can expose it.
Dump from a Vitess read-only region
Read-only regions are separate from rdonly or replica tablets in the primary region. Discover the configured regions for the target keyspace, select a ready region by slug, display name, or ID, and pass it explicitly to the dump command.
# Inspect region, cluster size, and replica count first
pscale keyspace read-only-regions <database> <branch> <keyspace> \
--org <org> --format json
# Dump through a short-lived reader credential scoped to that region
pscale database dump <database> <branch> \
--org <org> \
--keyspace <keyspace> \
--read-only-region <region> \
--output ./pscale-dump
This workflow is Vitess-only. --read-only-region cannot be combined with --replica or --rdonly; those flags target tablet types in the primary region. Confirm the output path does not already exist and that local disk has sufficient space before starting a dump. If the selected region is not ready, wait rather than silently falling back to the primary region.
Current dump behavior propagates cursor-close and worker errors as a non-zero exit instead of logging and continuing. Treat any failed dump as incomplete even if some files exist; do not restore or publish partial output, and rerun into a fresh directory after resolving the underlying error.
Manage Vitess read-only regions
Use pscale database regions list <database> to discover regions currently available to a database, pscale database read-only-regions list <database> to discover configured read-only regions, and pscale size cluster list to discover valid cluster sizes. The database-scoped read-only-region command is Vitess-only; for PostgreSQL databases the CLI fetches the database to determine its engine and rejects it before calling the read-only-regions endpoint. Add/update require at least one sizing flag supported by the API. Removing a region can disrupt region-scoped readers, dumps, and passwords: inventory those dependencies, confirm the exact keyspace and region, obtain approval, run the removal, and verify the remaining list.
pscale database regions list <database> --org <org> --format json
pscale database read-only-regions list <database> --org <org> --format json
pscale keyspace read-only-regions add <database> <branch> <keyspace> <region> \
--org <org> --cluster-size <size> --replicas <count> --format json
pscale keyspace read-only-regions update <database> <branch> <keyspace> <region> \
--org <org> --replicas <count> --format json
pscale keyspace read-only-regions remove <database> <branch> <keyspace> <region> \
--org <org>
pscale keyspace read-only-regions <database> <branch> <keyspace> \
--org <org> --format json
Delete a Vitess keyspace
Keyspace deletion is destructive. Confirm the organization, database, branch, exact keyspace, routing/workflow dependencies, and recovery plan before asking for approval.
# Inspect the target and related branch state first
pscale keyspace show <database> <branch> <keyspace> --org <org> --format json
pscale branch vtctld get-keyspace-routing-rules <database> <branch> --org <org> --format json
pscale branch vtctld list-workflows <database> <branch> --org <org> \
--keyspace <keyspace> --format json
# Interactive deletion requires typing database/branch/keyspace exactly
pscale keyspace delete <database> <branch> <keyspace> --org <org>
# Non-interactive deletion only after explicit approval
pscale keyspace delete <database> <branch> <keyspace> --org <org> --force --format json
# Verify absence and inspect remaining keyspaces
pscale keyspace list <database> <branch> --org <org> --format json
Without --force, the CLI first verifies the keyspace exists and requires a TTY confirmation of <database>/<branch>/<keyspace>. JSON/CSV or headless execution requires --force; never add it simply to bypass the safety prompt.
Create an external Vitess keyspace
create-external connects a production Vitess branch to an existing MySQL database. Treat this as an infrastructure and data-movement change. Confirm the organization, PlanetScale database, production branch, new keyspace name, remote database, network path, TLS policy, target size, ownership, and rollback plan before creation.
# Discover sizes intended for external keyspaces
pscale size cluster list --org <org> --external --format json
# Have the user or an approved secret manager inject SOURCE_PASSWORD into this
# same trusted one-shot shell. Never ask for it in chat or write it to a file.
(
set -euo pipefail
trap 'unset SOURCE_PASSWORD DRY_RUN_JSON SSL_CA_PATH' EXIT
: "${SOURCE_PASSWORD:?source password not set}"
: "${SSL_CA_PATH:?reviewed CA path not set}"
test -r "$SSL_CA_PATH"
DRY_RUN_JSON="$(
pscale keyspace create-external <database> <production-branch> <keyspace> \
--org <org> --host <host> --port 3306 \
--source-database <remote-database> --username <user> \
--password "${SOURCE_PASSWORD:?source password not set}" \
--ssl-mode verify_identity --ssl-server-name <server-name> \
--ssl-certificate-authority "$SSL_CA_PATH" \
--cluster-size <external-size> --dry-run --format json
)"
jq '{can_connect, lint_errors, has_foreign_keys, server_version, total_storage_bytes}' \
<<<"$DRY_RUN_JSON"
jq -e '.can_connect == true and (.error // "") == "" and ((.lint_errors // []) | length == 0)' \
<<<"$DRY_RUN_JSON" >/dev/null
)
# After the dry-run shell exits, review every displayed field and obtain approval.
# Then inject SOURCE_PASSWORD afresh into the same shell that performs the create.
(
set -euo pipefail
trap 'unset SOURCE_PASSWORD SSL_CA_PATH' EXIT
: "${SOURCE_PASSWORD:?source password not set}"
: "${SSL_CA_PATH:?reviewed CA path not set}"
test -r "$SSL_CA_PATH"
pscale keyspace create-external <database> <production-branch> <keyspace> \
--org <org> --host <host> --port 3306 \
--source-database <remote-database> --username <user> \
--password "${SOURCE_PASSWORD:?source password not set}" \
--ssl-mode verify_identity --ssl-server-name <server-name> \
--ssl-certificate-authority "$SSL_CA_PATH" \
--cluster-size <external-size> --wait --format json
)
pscale keyspace show <database> <production-branch> <keyspace> \
--org <org> --format json
Required connection flags are --host, --source-database, --username, --password, and --ssl-mode. Prefer verify_identity with a reviewed CA and server name; do not weaken TLS merely to make a dry run pass. Do not carry a source password across an approval boundary: let the dry-run shell clear its local copy, then have the user or approved secret manager inject it afresh into the one-shot create shell. If a parent shell exported the variable, clear that parent copy immediately after each command. Keep credentials out of shell history, logs, PRs, and command transcripts; never invent or persist the source password. Because the CLI accepts the password as a flag, command-line process inspection can expose it transiently: run from a trusted host and minimize concurrent access.
Certificate flags accept PEM text or a file path. When a path is intended, verify each CA, client-certificate, and client-key file with test -r or use a reviewed absolute path before invoking pscale: an unreadable or mistyped path is otherwise treated as literal certificate text.
The dry run checks connectivity and returns schema lint findings without creating the keyspace, but lint findings do not make the CLI exit non-zero. Gate the workflow on structured JSON: require can_connect: true, an empty error, and an empty lint_errors array, then review has_foreign_keys, server_version, and total_storage_bytes. A normal create can still proceed over table-level lint errors even without --skip-lint-errors, so it is not a lint backstop. Do not use --skip-lint-errors unless the organization allows it, every lint error has been reviewed, and the user explicitly approves bypassing those exact findings. Omit --cluster-size only when allowing PlanetScale to select from source storage is intentional. Do not use internal-keyspace --additional-replicas for external keyspaces.
Vitess keyspace throttler settings
Inspect the keyspace settings first. The JSON result may include the keyspace throttler's enabled state and replication-lag threshold. This persisted database/keyspace settings API, pscale keyspace update-settings --throttler-*, is distinct from live vtctld tablet/keyspace throttler policy under pscale branch vtctld throttler ... --keyspace. It is also separate from the database default and per-deploy-request ratios.
# Read current replication and throttler settings
pscale keyspace settings <database> <branch> <keyspace> \
--org <org> --format json
# Disable the keyspace throttler explicitly
pscale keyspace update-settings <database> <branch> <keyspace> \
--org <org> --throttler-enabled=false --format json
# Enable it with an explicit non-negative lag threshold in seconds
pscale keyspace update-settings <database> <branch> <keyspace> \
--org <org> --throttler-enabled=true --throttler-threshold=5 --format json
# Change only the threshold; the CLI preserves the current enabled state
pscale keyspace update-settings <database> <branch> <keyspace> \
--org <org> --throttler-threshold=10 --format json
# Change rollout concurrency after reviewing shard count and migration capacity
pscale keyspace update-settings <database> <branch> <keyspace> \
--org <org> --max-rollout=2 --format json
# Verify the persisted state after any update
pscale keyspace settings <database> <branch> <keyspace> \
--org <org> --format json
--throttler-enabled is a boolean flag with a displayed default of true. Always pass it as --throttler-enabled=true or --throttler-enabled=false. Do not use the space-separated form --throttler-enabled false: pflag treats the bare boolean flag as true and leaves false as a positional argument, so operator intent is ambiguous and unsafe. --throttler-threshold accepts seconds as a floating-point value and rejects values below zero.
For a threshold-only update, the CLI sends only the threshold field and leaves enabled unset, so the API preserves the current enabled state without the CLI fetching or resending unrelated setting groups. Likewise, an enabled-only update omits the threshold. This focused-payload behavior is specific to the throttler group; verify the preserved sibling field from a fresh settings read after every update.
pscale keyspace settings --format json prints the raw keyspace resource, so throttler can be null on an unconfigured keyspace and max_rollout can be absent. When throttler is present, enabled and threshold can still be absent; a present threshold is a JSON number. Human and CSV output are display-oriented: thresholds append s, and unset values may appear as not set. Use null-safe checks such as jq '{max_rollout, throttler: (.throttler // {})}' instead of assuming every key exists.
--max-rollout accepts 1 through 32 and controls how many shards receive changes concurrently. Higher concurrency can increase rollout load and reduce the opportunity to stop between shards. Inspect current settings and shard count, propose the smallest sufficient value, obtain approval, update only that field, then re-read max_rollout from JSON.
Changing throttler settings affects live migrations and replication workflows. Confirm the organization, database, branch, keyspace, current state, desired enabled state, and threshold; obtain explicit approval before any update; then re-read the settings instead of trusting only the update response.
Avoid pscale keyspace update-settings --interactive unless you intentionally want to review and write the durability, VReplication, and throttler groups shown by the form. The interactive path returns before explicit flag handling, so do not combine it with flags. It can seed an absent throttler to enabled=true and threshold=5 if defaults are accepted, and emits only a human success line even with --format json; do not rely on JSON output from the interactive write for verification. Re-run pscale keyspace settings --format json after any interactive update.
Non-interactive updates send only changed top-level groups, with one important exception inside VReplication: changing any --vreplication-* flag first fetches the current keyspace, copies all three VReplication flags, overrides the requested flag, and resends the complete group because the API replaces that group wholesale. A concurrent sibling-flag update can therefore be overwritten. Read fresh settings immediately before a VReplication change, avoid concurrent updates, and re-read all three VReplication flags afterward. Durability, throttler, and --max-rollout updates do not implicitly rewrite the other top-level groups.
Do not use --disk-scaling-strategy or --max-storage with pscale keyspace update-settings; they are not supported there and have no CLI replacement. Inspect current help and use the PlanetScale UI/API only under its own documented and approved workflow.
Troubleshooting
Cannot create database
Error: "Organization limit reached"
Solution: Upgrade plan or delete unused databases
Shell connection fails
Error: "Authentication failed"
Solution:
# Re-authenticate
pscale auth logout && pscale auth login
# Verify branch exists
pscale branch list <database>
Related Skills
- pscale-branch - Manage database branches
- pscale-password - Create connection passwords for databases
References
See references/commands.md for complete command reference.