# Create and manage server databases

> Create a MySQL-compatible database for your server, read its credentials, rotate its password and delete it.

Source: https://docs.coritan.com/managed-containers/databases/

In the dashboard:

- /dashboard/servers/…/databases: https://www.coritan.com/dashboard/servers

Many plugins and mods keep their data in a MySQL database: permissions, economy balances, player statistics. The **Databases** tab creates MariaDB databases for your server, which work with any plugin that asks for MySQL. We create each one on a shared MariaDB host in the server's region.

## Before you begin

- Your plan sets how many databases the server can have. The **Databases** card shows how many slots you have used, and [Server settings](/managed-containers/settings/) shows the plan's **Database slots**.
- Free servers do not include databases. See [How free servers work](/managed-containers/free-servers/).
- On a server someone shared with you, the owner must have given you the Databases permission.

## Create a database

1. In the [dashboard](https://www.coritan.com/dashboard/servers), go to **Container Apps** and open the server, then the **Databases** tab.
2. Select **New database…**.
3. Enter a **Name suffix** that says what the database is for, such as `stats` or `luckperms`. Use lowercase letters, digits and underscores, up to 48 characters.
4. Leave **Database host** as it is. We always use the host in the server's region, whatever it says.
5. Select **Create database**.

The database's name is `srv_`, your server's number, an underscore and your suffix, such as `srv_1234_stats`. We create a user for it with a random 24-character password.

## Connect a plugin to it

1. Select the database's name, or open the menu at the end of its row and select **Show credentials**.
2. Copy the values into your plugin's configuration file. Select **Reveal** to see the password, or **Copy all** to copy every value at once.
3. Restart the server so the plugin connects.

**Host**
: The address of the database server. Use this value rather than the **Host** column in the list.

**Port**
: Usually `3306`.

**Database**
: The database's name, such as `srv_1234_stats`.

**Username** and **Password**
: The database user. You can show the password again at any time.

**Connection URI**
: The same details in one `mysql://` address, for plugins that ask for a URL. It includes the password.

**JDBC**
: The same details as a `jdbc:mysql://` address, for Java plugins that ask for one. It includes the password.

## Rotate the password

Rotate the password when you think someone else has seen it.

1. Open the menu at the end of the database's row and select **Rotate password…**.
2. Select **Rotate password**.
3. Copy the new password from the window that opens, and put it in every plugin that uses the database.

> [!IMPORTANT]
> The old password stops working straight away. Plugins that use it cannot reach the database until you give them the new one and restart the server.

## Delete a database

1. Open the menu at the end of the database's row and select **Delete database…**.
2. Type the database's name to confirm, then select **Delete database**.

We delete the database and every table in it, and you cannot undo it. A [snapshot](/managed-containers/snapshots/) holds the server's files, not its databases, so export anything you want to keep first with a plugin or a MySQL client.

## Result

A new database shows in the list with its user under the name, and its credentials open straight away. The **Status** column shows each database's state, and a message confirms each action, such as `Database created.` or `Database deleted.`

## Troubleshooting

The status shows a failure and **Try again**
: We could not finish creating, rotating or deleting the database. The error shows under its name. We keep trying on our own, and **Try again** tries at once. If it keeps failing, [contact support](https://www.coritan.com/dashboard/support) with the error.

**New database…** is greyed out
: Every database slot is in use. Delete a database you no longer need, or move to a plan with more slots. See [Change a service's plan](/billing/change-plan/).

`Database limit reached (3/3)`
: The same limit, reached through the API or another tab. The numbers are your database count and your plan's limit.

`A database named srv_1234_stats already exists on this host`
: The server already has a database with that suffix. Choose another suffix.

`The database host is unreachable. We will keep trying; you can also retry from the list.`
: The database host did not answer. We keep trying, and the database finishes when the host is back. Select **Try again** to retry sooner.

`No database host on this server's node`
: Databases are not available where your server runs. [Contact support](https://www.coritan.com/dashboard/support).

`Retry the failed create before rotating the password`
: The database was never created. Select **Try again** first, then rotate the password.

`Too many requests for this action. Please wait and try again.`
: You created more than 24 databases on this server in 60 seconds. Wait a minute and try again.

## Related

- [Manage server files](/managed-containers/files/) to edit the plugin's configuration file.
- [Share a server with other users](/managed-containers/users/) explains the Databases permission.
- [Server limits and rate limits](/managed-containers/limits/)

## With the API

Create a database with `POST /api/v1/client/servers/{uuid}/databases`. The body takes `name_suffix` (lowercase letters, digits and `_`, up to 48 characters) and `remote`, a MariaDB host pattern for where the user may connect from. `remote` defaults to `%`, which allows any address. We choose the database host, so any `database_host_id` you send is ignored.

```bash
curl -X POST https://api.coritan.com/api/v1/client/servers/$SERVER/databases \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: create-stats-db-1" \
  -d '{"name_suffix": "stats"}'
```

The response (`201`) carries `id`, `name`, `username`, `password`, `host`, `port`, `uri`, `jdbc` and `status`. With an `Idempotency-Key` header, sending the same request again returns the same database instead of a second one. See [Idempotency](/api/idempotency/).

The other routes use the database's `id`:

| Route | What it does |
|---|---|
| `GET /api/v1/client/servers/{uuid}/databases` | Lists the server's databases, without passwords. |
| `GET /api/v1/client/servers/{uuid}/databases/{db_id}/credentials` | Returns one database with its `password`, `uri` and `jdbc`. |
| `POST /api/v1/client/servers/{uuid}/databases/{db_id}/rotate-password` | Sets a new password and returns it. |
| `POST /api/v1/client/servers/{uuid}/databases/{db_id}/retry` | Finishes a create, rotation or deletion that failed. |
| `DELETE /api/v1/client/servers/{uuid}/databases/{db_id}` | Deletes the database and everything in it. |

Each database has a `status`: `ready`, `provisioning` while we create it, `rotating`, `deleting`, or `failed`. `busy` is `true` during the three in-between states, and `last_error` holds the reason for a failure. Errors carry an `error` code and a `message`: `database_limit_reached`, `database_name_taken`, `database_busy` and `database_not_ready` answer `409`, and `database_host_unreachable` answers `503`.

On a server shared with you, listing needs `database.read`, creating and retrying need `database.create`, rotating needs `database.update`, reading the password needs `database.view_password` and deleting needs `database.delete`. The Databases permission in the dashboard grants all five.

## API

- `GET /api/v1/client/servers/{uuid}/databases`: List databases for a server (https://docs.coritan.com/api/reference/client/container-apps/servers-databases/#op-get-api-v1-client-servers-uuid-databases)
- `POST /api/v1/client/servers/{uuid}/databases`: Create a new database (https://docs.coritan.com/api/reference/client/container-apps/servers-databases/#op-post-api-v1-client-servers-uuid-databases)
- `DELETE /api/v1/client/servers/{uuid}/databases/{db_id}`: Delete a database (https://docs.coritan.com/api/reference/client/container-apps/servers-databases/#op-delete-api-v1-client-servers-uuid-databases-db-id)
- `GET /api/v1/client/servers/{uuid}/databases/{db_id}/credentials`: Reveal the stored password for a database on this server (https://docs.coritan.com/api/reference/client/container-apps/servers-databases/#op-get-api-v1-client-servers-uuid-databases-db-id-credentials)
- `POST /api/v1/client/servers/{uuid}/databases/{db_id}/retry`: Retry a failed or stuck database operation (https://docs.coritan.com/api/reference/client/container-apps/servers-databases/#op-post-api-v1-client-servers-uuid-databases-db-id-retry)
- `POST /api/v1/client/servers/{uuid}/databases/{db_id}/rotate-password`: Rotate database password (https://docs.coritan.com/api/reference/client/container-apps/servers-databases/#op-post-api-v1-client-servers-uuid-databases-db-id-rotate-password)
