---
title: How to Secure PostgreSQL Managed Database Clusters
description: Secure PostgreSQL managed database clusters by restricting inbound connections with trusted sources and strengthening TLS verification with sslmode …
product: Databases
url: https://docs.digitalocean.com/products/databases/postgresql/how-to/secure/
last_updated: "2026-08-03"
---

> **For AI agents:** The documentation index is at [https://docs.digitalocean.com/llms.txt](https://docs.digitalocean.com/llms.txt). Markdown versions of pages use the same URL with `index.html.md` in place of the HTML page (for example, append `index.html.md` to the directory path instead of opening the HTML document).

# How to Secure PostgreSQL Managed Database Clusters

PostgreSQL is an open source, object-relational database built for extensibility, data integrity, and speed. Its concurrency support makes it fully ACID-compliant, and it supports dynamic loading and catalog-driven operations to let users customize its data types, functions, and more.

DigitalOcean managed PostgreSQL database clusters encrypt data at rest with LUKS (Linux Unified Key Setup) and in transit with TLS. Restrict inbound connections with trusted sources and strengthen TLS verification with `sslmode` settings such as `verify-full`.

## Restrict Incoming Connections

You can greatly decrease the likelihood of a security breach by restricting which DigitalOcean resources or external IP addresses are allowed to access the nodes in a cluster. This prevents brute force password and denial-of-service attacks from any server not explicitly permitted to connect.

Typically, only application servers are allowed to connect to the database cluster. Users access the public-facing site, and the public-facing server authenticates and manages database connections in turn.

To implement these restrictions, add trusted sources, which define the resources or IP addresses allowed to connect to the database cluster.

## Add a Trusted Source Using Automation

You can add trusted sources using the DigitalOcean CLI (`doctl`) or the API.

### Add a Trusted Source via CLI

To add a trusted source using `doctl`, use `doctl databases firewalls append` with the database cluster ID and the trusted source type and value.

## How to Add a Trusted Source Using the DigitalOcean CLI

1. [Install `doctl`](https://docs.digitalocean.com/reference/doctl/how-to/install/index.html.md), the official DigitalOcean CLI.
2. [Create a personal access token](https://docs.digitalocean.com/reference/api/create-personal-access-token/index.html.md) and save it for use with `doctl`.
3. Use the token to grant `doctl` access to your DigitalOcean account.

   ```shell
   doctl auth init
   ```
4. Finally, run `doctl databases firewalls append`. Basic usage looks like this, but you can [read the usage docs](https://docs.digitalocean.com/reference/doctl/reference/databases/firewalls/append/index.html.md) for more details:

   ```shell
   doctl databases firewalls append <database-cluster-id> --rule <type>:<value> [flags]
   ```

   The following example appends a firewall rule to a database cluster with the ID `ca9f591d-f38h-5555-a0ef-1c02d1d1e35` that allows any resources with the `example-tag` to access the database:

   ```shell
   doctl databases firewalls append ca9f591d-f38h-5555-a0ef-1c02d1d1e35 --rule tag:example-tag
   ```

For list, remove, and other firewall commands, see [`doctl databases firewalls`](https://docs.digitalocean.com/reference/doctl/reference/databases/firewalls/index.html.md).

### Add a Trusted Source via API

To add a trusted source using the API, send a `PUT` request to the database firewall endpoint with the cluster ID and the trusted source type and value.

## How to Add or Remove a Trusted Source Using the DigitalOcean API

[Create a personal access token](https://docs.digitalocean.com/reference/api/create-personal-access-token/index.html.md) and save it for use with the API.

### cURL

Send a PUT request to [`https://api.digitalocean.com/v2/databases/{database_cluster_uuid}/firewall`](https://docs.digitalocean.com/reference/api/reference/databases/index.html.md#databases_update_firewall_rules).

Using cURL:

```shell
curl -X PUT \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
  -d '{"rules": [{"type": "ip_addr","value": "192.168.1.1"},{"type": "droplet","value": "163973392"},{"type": "k8s","value": "ff2a6c52-5a44-4b63-b99c-0e98e7a63d61"},{"type": "tag","value": "backend"}]}' \
  "https://api.digitalocean.com/v2/databases/9cc10173-e9ea-4176-9dbc-a4cee4c4ff30/firewall"
```

### Go

Using [Godo](https://github.com/digitalocean/godo), the official DigitalOcean API client for Go:

```go
import (
    "context"
    "os"

    "github.com/digitalocean/godo"
)

func main() {
    token := os.Getenv("DIGITALOCEAN_TOKEN")

    client := godo.NewFromToken(token)
    ctx := context.TODO()

    req := godo.DatabaseUpdateFirewallRulesRequest{
      Rules: []*godo.DatabaseFirewallRule{
        {
         Type:  "ip_addr",
         Value: "192.168.1.1",
         Description: "a development IP address",
       },
        {
         Type:  "droplet",
         Value: "163973392",
       },
        {
         Type:  "k8s",
         Value: "ff2a6c52-5a44-4b63-b99c-0e98e7a63d61",
        },
      },
    }
    _, err := client.Databases.UpdateFirewallRules(ctx, dbID, &req)
}
```

### Python

Using [PyDo](https://github.com/digitalocean/pydo), the official DigitalOcean API client for Python:

```python
import os
from pydo import Client

client = Client(token=os.environ.get("DIGITALOCEAN_TOKEN"))

req = {
  "rules": [
    {
      "type": "ip_addr",
      "value": "192.168.1.1",
      "description": "a development IP address",
    },
    {
      "type": "k8s",
      "value": "ff2a6c52-5a44-4b63-b99c-0e98e7a63d61"
    },
    {
      "type": "droplet",
      "value": "163973392"
    },
    {
      "type": "tag",
      "value": "backend"
    }
  ]
}
update_resp = client.databases.update_firewall_rules(database_cluster_uuid="a7a8bas", body=req)
```

## Make Bulk Updates to Trusted Sources Using Automation

Bulk updates replace the cluster’s full trusted sources list. Use them when you need to add, remove, or replace multiple trusted sources in one operation.

### Make Bulk Updates to Trusted Sources via CLI

To make bulk updates using `doctl`, use `doctl databases firewalls replace` with the full list of trusted sources you want the cluster to keep.

## How to Make Bulk Updates to Trusted Sources Using the DigitalOcean CLI

To add, remove, or replace multiple trusted sources in one `doctl` command, replace the cluster’s full firewall rule list with [`doctl databases firewalls replace`](https://docs.digitalocean.com/reference/doctl/reference/databases/firewalls/replace/index.html.md).

Pass the rules you want to keep using comma-separated `type:value` entries in the `--rules` flag. Each entry uses:

- `type`: `droplet`, `k8s`, `ip_addr`, `tag`, or `app`
- `value`: the resource ID, Kubernetes cluster UUID, IP address or CIDR range, tag name, or App identifier, depending on `type`

The rules you pass to `replace` become the cluster’s full trusted sources list. Any existing rule you omit is removed. To change the list safely, first list the current rules with [`doctl databases firewalls list`](https://docs.digitalocean.com/reference/doctl/reference/databases/firewalls/list/index.html.md), then run `replace` with the full set of `type:value` entries you want to keep. Clusters are limited to 100 firewall rules.

**Warning**:

  You currently cannot add IPv6 rules to a database cluster’s trusted sources.

For required flags, examples, and output formats, see [`doctl databases firewalls replace`](https://docs.digitalocean.com/reference/doctl/reference/databases/firewalls/replace/index.html.md).

### Make Bulk Updates to Trusted Sources via API

To make bulk updates using the API, send a `PUT` request to the database firewall endpoint with the full list of trusted sources you want the cluster to keep.

## How to Make Bulk Updates to Trusted Sources Using the DigitalOcean API

To add, remove, or replace multiple trusted sources in a single operation, send a `PUT` request to `/v2/databases/{database_cluster_uuid}/firewall` with a JSON body that contains a `rules` array.

Each object in `rules` supports:

- `type` (required): `droplet`, `k8s`, `ip_addr`, `tag`, or `app`
- `value` (required): the resource ID, Kubernetes cluster UUID, IP address or CIDR range, tag name, or App identifier, depending on `type`
- `description` (optional): a short note; this appears as the rule label in the Control Panel

The rules in your request become the cluster’s full firewall rule list. Any existing rule you omit is removed. To change the list safely, first [list firewall rules](https://docs.digitalocean.com/reference/api/reference/databases/index.html.md#databases_list_firewall_rules) with `GET /v2/databases/{database_cluster_uuid}/firewall`, edit the returned `rules` array, then send your updated array with `PUT` to the same path. A successful update returns `204 No Content`. Clusters are limited to 100 firewall rules.

**Warning**:

  You currently cannot add IPv6 rules to a database cluster’s trusted sources.

For example payloads, authentication, and required OAuth scopes (`database:read` to list, `database:update` to change rules), see [Update firewall rules (trusted sources) for a database](https://docs.digitalocean.com/reference/api/reference/databases/index.html.md#databases_update_firewall_rules) in the Databases API reference.

## Add a Trusted Source Using the Control Panel

**Note**:

  In the Control Panel, you can make bulk changes to trusted sources, but each source must be entered manually. To update many rules at once or replace the entire list in a single operation, use the [API or CLI to make bulk updates to trusted sources](#make-bulk-updates-to-trusted-sources-using-automation).

To add trusted sources to restrict database access, go to the [**Databases** page](https://cloud.digitalocean.com/databases) and select the cluster you want to add trusted sources to. Click the **Network Access** tab.

The **Network Access** page lists any trusted sources already added. An icon next to each trusted source indicates its resource type (for example, Droplet, App Platform app, tag, or Kubernetes cluster).

![The Network Access tab for an example cluster, showing trusted sources with resource type icons.](https://docs.digitalocean.com/screenshots/databases/cluster-network-access-table.4a6bb7e5702cc9fd337147dc02561de767a3f479b7d66d50f44819219a8ba84e.png)

Click **Add Trusted Sources**. In the **Add Trusted Sources** window, choose one of the following options:

- **Enter specific IP addresses or CIDR notations**: Enter specific IP addresses or a CIDR range. Or click **My current IP address** to use the **Quick Add** option, which adds your machine’s current IP address.

![The Add Trusted Sources window with the option Enter specific IP addresses or CIDR notations selected, and an example CIDR range shown.](https://docs.digitalocean.com/screenshots/databases/add-trusted-sources-ips-cidr.1cadefc47997cf52f706696bce6d1896d72b199be88731adf86792abce98cc36.png)

- **Quick select Droplets, Kubernetes clusters, Apps, and tags**: Use the search to find a resource, or open the dropdown and select a resource from the list. The dropdown groups resources by type, such as Droplets, Applications, tags, and Kubernetes clusters.

![The Add Trusted Sources window with the option Quick select Droplets, Kubernetes clusters, Apps, and tags selected, and the Search or select a resource dropdown menu expanded.](https://docs.digitalocean.com/screenshots/databases/add-trusted-sources-quick-select.e3832bfc4b4ae8086ce188320c3819e6bdaa55b41ce8a85fd6e5c6308fcd07d1.png)

When finished, click **Add Trusted Sources**.

**Warning**:

  You currently cannot add IPv6 rules to a database cluster’s trusted sources.

## Increase TLS Verification with `sslmode`

Managed PostgreSQL clusters require TLS for all connections. When you retrieve connection details from the Control Panel, API, or CLI, the response includes `ssl: true` and a connection URI with the client `sslmode` parameter set to `require`. This encrypts traffic in transit but does not verify the server identity. This protects administrative usernames, passwords, and data from eavesdropping.

Encryption alone does not protect against man-in-the-middle (MITM) attacks. Without verification, an attacker could impersonate the database server.

To verify the server, set `sslmode` to `verify-ca` or `verify-full`. Both validate the server certificate against a trusted certificate authority (CA), but they are disabled by default because they can affect performance. `verify-full` also checks that the server hostname matches the certificate and is the most secure option.

On Standard Edition and Advanced Edition clusters, enable **`verify-full`** when you [retrieve connection details in the Control Panel](https://docs.digitalocean.com/products/databases/postgresql/how-to/connect/index.html.md#connection-details). Generated connection values differ by edition. Standard Edition includes a CA certificate path, and Advanced Edition uses your system’s trust store.

On PostgreSQL Standard Edition clusters, in `psql`, the `--set=sslmode=...` option only sets a psql script variable. It does not configure TLS for the connection. The Control Panel default flags command uses `--set=sslmode=require`, but that option does not enable TLS either.

### Standard Edition

To verify the server certificate over TLS on Standard Edition clusters, set the `PGSSLMODE` and `PGSSLROOTCERT` [environment variables](https://www.postgresql.org/docs/current/libpq-envars.html), and provide the path to the CA certificate you [downloaded from the Control Panel](https://docs.digitalocean.com/products/databases/postgresql/how-to/connect/index.html.md#download-the-ssl-certificate) when using `verify-ca` or `verify-full`.

For example, to connect with `verify-full` (recommended), replace `<your-password>`, `<your-cluster-hostname>`, `<your-cluster-port>`, and `<path-to-ca-certificate>` with your password, cluster hostname, port from **Connection Details**, and path to your downloaded CA certificate:

```shell
PGPASSWORD=<your-password> \
PGSSLMODE=verify-full \
PGSSLROOTCERT=<path-to-ca-certificate> \
psql -U doadmin -h <your-cluster-hostname> -p <your-cluster-port> -d defaultdb
```

### Advanced Edition

To verify the server certificate over TLS on Advanced Edition clusters, set `PGSSLMODE=verify-full`. `libpq`-based clients such as `psql` also require the system trust store: set `PGSSLROOTCERT=system` for Flags, or include `sslrootcert=system` in the connection URI. You do not download a CA certificate file. Use a PostgreSQL client with `libpq` 16 or later when you set `sslrootcert=system`. Older `libpq` versions treat `system` as a filename and the connection fails.

The Control Panel copy action includes `sslmode=verify-full` but does not add `sslrootcert=system` or `PGSSLROOTCERT=system`. Add that value before you connect with `psql`.

For example, to connect with `verify-full` (recommended), replace `<your-password>`, `<your-cluster-hostname>`, and `<your-cluster-port>` with your password, cluster hostname, and port from **Connection Details**:

```shell
PGPASSWORD=<your-password> \
PGSSLMODE=verify-full \
PGSSLROOTCERT=system \
psql -U doadmin -h <your-cluster-hostname> -p <your-cluster-port> -d defaultdb
```

Or pass a connection URI with `sslrootcert=system`:

```shell
psql "postgresql://doadmin:<your-password>@<your-cluster-hostname>:<your-cluster-port>/defaultdb?sslmode=verify-full&sslrootcert=system"
```

For URI connection strings, DataGrip, and other client setup steps, see [Connect to the Cluster](https://docs.digitalocean.com/products/databases/postgresql/how-to/connect/index.html.md#connect-to-the-database).

For details on `libpq` SSL modes and client configuration, see [PostgreSQL’s `libpq` SSL documentation](https://www.postgresql.org/docs/current/libpq-ssl.html).