
Azure Database for PostgreSQLAuthorCloudBrum editorial teamLast reviewedReading time~12 minLevelBeginner to advanced
Microsoft Azure · Databases · Managed PostgreSQL
PostgreSQL that Microsoft runs for you. The service today is the flexible server: you choose a version, a size and whether the database sits inside your virtual network, and Azure handles patching, backups and failover. The decisions that are hard to change later are the network mode (private or public) and the backup redundancy, so make them before you create the server rather than after.
On this page (17 sections)
Mind map: Azure Database for PostgreSQL at a glance
Free to share. The downloaded image includes the CloudBrum link.
Key features (summary)
- Real PostgreSQLIt’s community PostgreSQL, so drivers, ORMs and extensions behave as you expect. Several major versions are offered at once, and older ones can run on paid extended support.
- Three compute tiersBurstable servers for dev and light use, General Purpose for most applications and Memory Optimized for large working sets. You can change the tier later, with a restart.
- High availability across zonesWith high availability on, Azure keeps a standby that is copied synchronously, either in another zone (zone-redundant) or in the same one. If the primary fails, the standby takes over under the same server name.
- Backups you don’t scheduleBackups run automatically, and you pick how long to keep them, from 7 to 35 days. Point-in-time restore builds a new server at the moment you choose.
- Read replicasUp to five asynchronous replicas, in the same Region or another, for reporting and read scale. Replicas can be promoted to stand-alone servers.
- Private or publicPrivate access puts the server inside your virtual network on a subnet you delegate to it, with no public endpoint. Public access uses a firewall that blocks everything until you add rules.
- Microsoft Entra sign-inConnect with an Entra identity and a short-lived token instead of a stored password, and turn password login off if you want to.
- A pooler already installedPgBouncer is built in. Turn on one server parameter and connect to port 6432 to share connections between many clients.
Basic concepts
- Flexible server
- The current deployment model. It runs in your chosen zone, lets you stop and start the server, and offers private networking. The older Single Server model has been retired.
- Compute tier and SKU
- A tier (Burstable, General Purpose or Memory Optimized) plus a size such as Standard_D2ds_v5. It sets vCores and memory, and therefore the connection limit.
- Storage and IOPS
- A provisioned disk. Storage can grow but not shrink, and IOPS depend on the disk size or, with the faster disk type, on values you set yourself.
- High availability
- A standby server that is kept in step with the primary. It’s either zone-redundant (another zone) or same-zone, and it doesn’t answer queries.
- Read replica
- A copy that follows the primary asynchronously and answers read-only queries. It lags a little, and it can be promoted.
- Private access
- The server gets a private IP in a subnet of your virtual network, and clients find it through a private DNS zone.
- Public access
- The server has a public name, and a firewall rule list decides which addresses may connect. Without a rule, nobody gets in.
- Delegated subnet
- A subnet reserved for flexible servers. Nothing else can be placed in it.
- Server parameter
- An engine setting, such as max_connections or pgbouncer.enabled. Some apply at once, and others need a restart.
- Microsoft Entra authentication
- Sign-in with an Entra user, group or managed identity. The token you send as the password expires after about an hour.
- Point-in-time restore
- Creates a new server from the base backups and logs at a time you choose. The original isn’t touched.
- Maintenance window
- A monthly slot, which you can choose, when Azure applies updates that need a restart.
- Extension allow-list
- Extensions must be named in the azure.extensions parameter before you can run CREATE EXTENSION.
- Geo-redundant backup
- A copy of the backups in the paired Region, chosen when you create the server, so you can restore after a Regional disaster.
How to create & configure it
Create a private flexible server in the Azure portal
- Choose the Region and the network firstPick a Region close to the application (Central India for many Indian teams). Decide now whether the server will be private, because switching between private and public access later isn’t possible for the same server. Private access needs a virtual network in the same Region.
- Start the create wizardSearch for Azure Database for PostgreSQL flexible servers and choose Create. Pick the Flexible server option, a subscription, a resource group, a server name (unique across Azure) and the PostgreSQL version.
- Choose the workload type and sizeThe Development preset gives a small Burstable server. For production, use General Purpose and size by vCores and memory. A common start is two or four vCores.
- Turn on high availabilityUnder High availability, choose zone-redundant if the Region has zones, or same-zone if it doesn’t. It adds a standby, and it roughly doubles the compute and storage price.
- Set authenticationChoose Microsoft Entra authentication only if your tools support it, or PostgreSQL and Entra together. Name an Entra administrator so someone can sign in and create the other users.
- Pick the storageChoose the storage size, turn on storage autogrow, and for demanding workloads consider the faster disk type where IOPS and throughput are set separately.
- Choose private accessOn the Networking tab pick Private access (VNet integration), then select or create a virtual network, a delegated subnet and a private DNS zone. If you must use public access, add only the firewall rules you need.
- Set backups and tagsChoose a retention between 7 and 35 days, and decide on geo-redundant backup now, because it’s set at creation. Add tags for owner and cost centre.
- Connect and testConnect from a VM or app in the virtual network with SSL on, create an application role with limited rights, and test a point-in-time restore to a new server before you rely on it.
Tip: the wizard hides how many settings there are. Once you’ve seen them, write the server as code (the Azure CLI, Bicep or Terraform, see the code references) so network mode, availability and backup settings are decided in a review, not by whoever is clicking.
Common issues after configuration
| Symptom | Likely cause | What to check / fix |
|---|---|---|
| Connection times out | The firewall, network route or DNS isn’t set up for the server’s access mode | For public access, check the firewall rules and that your current IP is on the list. For private access, check you are inside the virtual network (or peered to it) and that the private DNS zone is linked to it. |
| The name resolves to a public address when you expected a private one | The private DNS zone isn’t linked to the client’s virtual network | Link the zone to every network that needs it, including peered and hub networks, and flush the resolver cache. |
| A PostgreSQL error that says the connection has no encryption | The server requires secure connections, and the client sent none | Connect with sslmode=require or better, verify-full, and don’t switch off require_secure_transport to make the error go away. |
| password authentication failed with Entra | The access token expired, or the identity isn’t mapped to a database role | Fetch a new token just before connecting (they last about an hour), and check that the Entra principal is added as a PostgreSQL role by the administrator. |
| remaining connection slots are reserved | The connection limit for the compute size was reached | Turn on the built-in PgBouncer and connect to port 6432, close idle connections in the application, and only then consider a bigger size. |
| extension "x" is not allow-listed | The extension wasn’t added to the azure.extensions parameter | Add it to the parameter, then run CREATE EXTENSION. A few extensions also need shared_preload_libraries and a restart. |
| The server is read-only and the disk is full | Storage ran out and autogrow was off | Increase the storage size (it can’t be reduced afterwards), find what grew, and turn on autogrow and a storage alert. |
| A stopped server started again by itself | Azure restarts a stopped server after the maximum stop period (seven days in the documentation we saw) | Plan for it, and use automation to stop it again if it’s a dev server. Remember storage and backups keep billing while it’s stopped. |
| The create or scale step fails with a capacity or SKU message | That size or zone-redundant option isn’t available in the Region or zone right now | Try another zone, size or tier, or a different Region. Zone-redundant HA needs a Region with zones. |
| Replica lag grows | Heavy writes on the primary or a smaller replica | Compare replica size with the primary, check long transactions on the replica, and watch the lag metric. |
| Surprise cost after a restore or replica test | Every restored server and replica bills like any other | Delete test servers straight away, and tag them so they show up in cost reports. |
Use cases: when and where to use it
Good fit
- Applications built on PostgreSQL that want a managed server with private networking inside Azure
- Teams that already use Microsoft Entra ID and want passwordless access to the database
- Moving a self-hosted PostgreSQL to a managed service with few code changes
- Web and API back ends that need transactions, JSON and extensions such as PostGIS
- Reporting copies of production data on read replicas
- Development and test servers that you can stop when nobody is working
Consider something else
- A SQL Server workload → Azure SQL Database, or SQL Managed Instance for server-level features
- MySQL applications → Azure Database for MySQL
- Globally distributed, schema-flexible data at huge scale → Azure Cosmos DB
- Analytics over very large tables → a warehouse or lakehouse, such as Fabric or Synapse, over Azure Blob Storage
- The same job on other clouds → compare Amazon RDS and Cloud SQL
Pros: why consider it?
Why teams choose it
- Standard PostgreSQL, with a wide choice of versions and allow-listed extensions
- Private networking and Entra sign-in fit naturally into an Azure estate
- Stop and start a server to avoid compute charges when it isn’t needed
- Built-in PgBouncer, so a pooler is a setting rather than a project
- Zone-redundant high availability and point-in-time restore without scripts
- Billing follows vCores and storage, so the cost is easy to estimate
Trade-offs to weigh
- Private or public access is a one-time choice for a server
- The high availability standby can’t serve reads, so scaling reads needs replicas
- Storage can’t be shrunk
- No superuser access, and extensions must be allow-listed
- Some settings, such as backup redundancy, are fixed at creation
- A stopped server restarts by itself after a week, which catches people out
Common threats, vulnerabilities & risks
| Risk | Severity | Why it matters | Mitigation |
|---|---|---|---|
| A server open to the internet | High | Public access with a broad firewall rule (or the allow-Azure option) exposes the database to anything that finds it. | Prefer private access. If public is unavoidable, allow specific addresses only and require SSL. |
| Stored admin passwords in application settings | High | A shared admin login is hard to rotate and leaks easily. | Use Entra authentication with managed identities, keep any remaining secrets in Key Vault, and turn password login off if you can. |
| Untested restore | High | You don’t know how long recovery takes or whether the backups hold what you expect. | Restore to a new server on a schedule, check the data and time the process. |
| No high availability on a production server | Medium | A zone problem or a maintenance event means an outage until the server returns. | Turn on high availability for production, and rehearse a forced failover. |
| Backup redundancy chosen carelessly | Medium | Geo-redundant backup is set at creation, so a Region outage can leave you without a restorable copy. | Decide on it when the server is created, based on your recovery targets. |
| Disk full | Medium | The server goes read-only, and storage can’t be reduced afterwards. | Autogrow on, an alert on storage used, and a look at table and log growth. |
| Over-privileged application roles | Medium | An app role that owns everything can drop tables as easily as read them. | Separate owner, migration and application roles, and grant the least privilege. |
| Old PostgreSQL versions | Low–Med | Retired versions lose fixes, and extended support is a paid way to buy time. | Track end-of-life dates and plan major upgrades in advance, testing on a restored copy. |
| Forgotten test servers and replicas | Low–Med | They bill for compute and storage until deleted. | Tag with an owner and expiry, and delete after use. |
Performance optimisation
- Size from metrics: CPU, memory, IOPS and the connection count. Move from Burstable to General Purpose when CPU credits run out regularly.
- Turn on PgBouncer and connect to port 6432 for applications with many short connections, such as serverless and web farms.
- Put the application and the server in the same Region and, where possible, the same zone to keep latency low.
- Choose the disk type for the workload. The faster disk type lets you set IOPS and throughput on their own instead of buying a bigger disk.
- Use read replicas for reports and dashboards, and watch replica lag.
- Find slow queries with pg_stat_statements and the query performance tools, then add indexes and look at plans before scaling up.
- Keep transactions short and avoid long idle-in-transaction sessions, which hold locks and delay cleanup.
- Tune autovacuum for write-heavy tables so bloat doesn’t slow every query.
Reduce monthly cost
FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Azure Database for PostgreSQL.
- Stop development and test servers when they aren’t in use. Compute billing stops, though storage and backups still bill, and Azure restarts a stopped server after about a week.
- Use Burstable servers for dev, test and low steady load, and General Purpose for production.
- Switch high availability off for non-production. It roughly doubles the bill.
- Look at reserved capacity for databases you’ll run for a year or three.
- Set backup retention to what you need. The free backup allowance is sized to your storage, and extra backup space is charged.
- Right-size after watching CPU and memory for a few weeks, and go down a size when the graphs are flat.
- Delete replicas and restored test servers as soon as you’ve finished with them.
- Don’t over-provision storage. It can grow when needed, but it can’t be shrunk.
- Use tags for owner, project and environment, and set budgets and alerts in Cost Management.
- Keep traffic inside the same Region to avoid transfer charges for cross-Region reads.
The prices and offers on this page are examples from Microsoft's public pages. Region, size and date all change them, so check the live figures first (see Pricing).
Security optimisation
- Choose private access with a delegated subnet and a private DNS zone, and turn off public network access where you can.
- Require SSL, and connect with sslmode=verify-full so clients check the server’s certificate.
- Use Microsoft Entra authentication with managed identities for applications, and keep the PostgreSQL password login disabled if every client supports Entra.
- Create separate roles for owners, migrations and applications, and grant only the privileges each needs.
- Use customer-managed keys in Key Vault where your policy requires them, and protect the vault with soft delete and purge protection.
- If you use public access, list specific addresses in the firewall and review them regularly.
- Send diagnostic logs and audit logs (pgAudit) to Log Analytics, and alert on failed sign-ins and changes to server parameters.
- Apply Azure Policy to require private access, backup settings and tags, and use Defender for Cloud for database posture checks.
- Restrict who can create, delete or reconfigure servers with Azure RBAC, and add resource locks to production servers.
- Keep the azure.extensions list short and review it when someone asks for a new extension.
Governance & compliance
Guardrails
- Policy that requires private access, SSL and backups on every server, and requires tags (owner, environment, data class, cost centre)
- A template (Bicep or Terraform) for servers with high availability, retention and diagnostics already set
- A list of approved versions, tiers and Regions, with the retirement date for each version
- A rule that only the deployment pipeline can create production servers
Rules to keep checking (Azure Policy, Defender for Cloud)
- A policy that denies public network access on flexible servers
- A policy that audits servers where SSL isn’t enforced
- An audit of servers without geo-redundant backup where your recovery targets need it
- An audit of servers that aren’t encrypted with customer-managed keys where policy requires them
- A custom rule for non-production servers that have run for more than a set time
The Activity log and Azure Monitor show who changed a server, Azure Policy enforces the rules above, Microsoft Defender for Cloud checks posture, and Microsoft Purview can catalogue the data. The Service Trust Portal holds compliance reports. Responsibility is split: Microsoft runs the platform and the patching, while you are accountable for the data, the roles, the network exposure and how recovery is tested.
Reduce carbon footprint
- Stop dev and test servers outside working hours. A server that isn’t running uses no compute.
- Right-size compute and storage, because idle capacity still draws power.
- Use read replicas only where reads really need them, and delete them when the job is done.
- Index and cache well, so each query reads less data and the same server serves more traffic.
- Keep backup retention to what recovery actually needs.
- Pick a Region with a cleaner grid for work that isn’t tied to a place, within your data rules.
- The Microsoft Emissions Impact Dashboard reports emissions per subscription. Look at how it counts databases before you quote a number from it.
Pricing
Purchase options
Compute Per vCore-hour
Billed by tier and size for each hour the server runs. A stopped server doesn’t bill for compute. High availability adds a second set of compute.
Storage and IOPS Per GB-month
Provisioned storage is billed whether or not it’s full. The faster disk type adds charges for the IOPS and throughput you set.
Backup storage Per GB-month
Backup space up to the size of your provisioned storage is free. Extra backup space, longer retention and geo-redundant copies add cost.
Extras Varies
Read replicas bill as full servers. Extended support for old versions, reserved capacity, network transfer between Regions and Log Analytics ingestion are separate lines.
What you actually pay for
- Compute by tier, size and hours running, doubled by high availability
- Provisioned storage, plus IOPS and throughput on the faster disk type
- Backup storage beyond the free allowance, longer retention and geo-redundant backup
- Read replicas, billed like separate servers
- Network transfer between Regions, Log Analytics data and extended support for retired versions
Prices vary by Region, tier and size, and change over time. Azure's free account has offered a small Burstable server for its first 12 months, so check what applies to yours. Use the official Azure Database for PostgreSQL pricing page and the Azure pricing calculator for current figures, and read the Azure free account page for credits and free services.
Important code references
The orders database again, this time on Azure: a private flexible server with zone-redundant high availability, 14 days of backups and Microsoft Entra sign-in, plus a read replica and a point-in-time restore. The CLI and Terraform tabs build it. The Python and C# tabs connect with an Entra token over verified TLS and place an order in a transaction. Names, the Entra administrator and the subscription are examples. A zone-redundant server bills from the moment it exists, so delete the test server afterwards.
# Names are examples; the server name must be unique across Azure.
RG=rg-orders
LOCATION=centralindia
SERVER=orders-pg-001
ADMIN_ID=00000000-0000-0000-0000-000000000000 # object ID of the Entra user or group that administers the server
az group create --name $RG --location $LOCATION
# The network first: a virtual network, a subnet delegated to PostgreSQL, and a private DNS zone linked to the network
az network vnet create --resource-group $RG --name vnet-orders --address-prefixes 10.20.0.0/16 \
--subnet-name snet-postgres --subnet-prefixes 10.20.1.0/24
az network vnet subnet update --resource-group $RG --vnet-name vnet-orders --name snet-postgres \
--delegations Microsoft.DBforPostgreSQL/flexibleServers
az network private-dns zone create --resource-group $RG --name orders.private.postgres.database.azure.com
az network private-dns link vnet create --resource-group $RG --zone-name orders.private.postgres.database.azure.com \
--name orders-pg-link --virtual-network vnet-orders --registration-enabled false
# The server: private access, zone-redundant high availability, Entra sign-in only.
# Older CLI versions spell the high availability switch --high-availability ZoneRedundant.
az postgres flexible-server create --resource-group $RG --name $SERVER --location $LOCATION \
--version 16 --tier GeneralPurpose --sku-name Standard_D2ds_v5 \
--storage-size 128 --storage-auto-grow Enabled \
--zonal-resiliency Enabled --zone 1 --standby-zone 2 \
--backup-retention 14 --geo-redundant-backup Disabled \
--vnet vnet-orders --subnet snet-postgres \
--private-dns-zone orders.private.postgres.database.azure.com \
--microsoft-entra-auth Enabled --password-auth Disabled \
--admin-object-id $ADMIN_ID --admin-display-name orders-db-admins --admin-type Group \
--tags owner=orders-team --yes
az postgres flexible-server db create --resource-group $RG --server-name $SERVER --name orders
# Turn on the built-in PgBouncer (clients then use port 6432)
az postgres flexible-server parameter set --resource-group $RG --server-name $SERVER --name pgbouncer.enabled --value true
# A read replica for reporting
az postgres flexible-server replica create --resource-group $RG --name orders-pg-replica --source-server $SERVER
# Practise the restore: a new server from the backups, at a time you choose (UTC)
az postgres flexible-server restore --resource-group $RG --name orders-pg-restore-test \
--source-server $SERVER --restore-time "2026-10-29T08:30:00Z"
# Clean up the test copy
az postgres flexible-server delete --resource-group $RG --name orders-pg-restore-test --yes
# Assumes the azurerm provider version 3.100 or later (or 4.x)
provider "azurerm" {
features {}
}
variable "admin_object_id" { type = string } # Entra user or group that administers the server
data "azurerm_client_config" "current" {}
resource "azurerm_resource_group" "orders" {
name = "rg-orders"
location = "centralindia"
}
resource "azurerm_virtual_network" "orders" {
name = "vnet-orders"
location = azurerm_resource_group.orders.location
resource_group_name = azurerm_resource_group.orders.name
address_space = ["10.20.0.0/16"]
}
# The subnet is delegated to PostgreSQL flexible servers; nothing else can live in it
resource "azurerm_subnet" "postgres" {
name = "snet-postgres"
resource_group_name = azurerm_resource_group.orders.name
virtual_network_name = azurerm_virtual_network.orders.name
address_prefixes = ["10.20.1.0/24"]
delegation {
name = "postgres"
service_delegation {
name = "Microsoft.DBforPostgreSQL/flexibleServers"
actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
}
}
}
resource "azurerm_private_dns_zone" "postgres" {
name = "orders.private.postgres.database.azure.com"
resource_group_name = azurerm_resource_group.orders.name
}
resource "azurerm_private_dns_zone_virtual_network_link" "postgres" {
name = "orders-pg-link"
resource_group_name = azurerm_resource_group.orders.name
private_dns_zone_name = azurerm_private_dns_zone.postgres.name
virtual_network_id = azurerm_virtual_network.orders.id
}
resource "azurerm_postgresql_flexible_server" "orders" {
name = "orders-pg-001"
resource_group_name = azurerm_resource_group.orders.name
location = azurerm_resource_group.orders.location
version = "16"
sku_name = "GP_Standard_D2ds_v5"
storage_mb = 131072
auto_grow_enabled = true
zone = "1"
backup_retention_days = 14
geo_redundant_backup_enabled = false
delegated_subnet_id = azurerm_subnet.postgres.id
private_dns_zone_id = azurerm_private_dns_zone.postgres.id
public_network_access_enabled = false
authentication {
active_directory_auth_enabled = true
password_auth_enabled = false
tenant_id = data.azurerm_client_config.current.tenant_id
}
high_availability {
mode = "ZoneRedundant"
standby_availability_zone = "2"
}
tags = { owner = "orders-team" }
depends_on = [azurerm_private_dns_zone_virtual_network_link.postgres]
}
resource "azurerm_postgresql_flexible_server_active_directory_administrator" "admin" {
server_name = azurerm_postgresql_flexible_server.orders.name
resource_group_name = azurerm_resource_group.orders.name
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = var.admin_object_id
principal_name = "orders-db-admins"
principal_type = "Group"
}
resource "azurerm_postgresql_flexible_server_database" "orders" {
name = "orders"
server_id = azurerm_postgresql_flexible_server.orders.id
charset = "UTF8"
collation = "en_US.utf8"
}
# Built-in PgBouncer on port 6432
resource "azurerm_postgresql_flexible_server_configuration" "pgbouncer" {
name = "pgbouncer.enabled"
server_id = azurerm_postgresql_flexible_server.orders.id
value = "true"
}
# pip install azure-identity "psycopg[binary]"
# The caller must be an Entra principal that the server's administrator has added as a PostgreSQL role.
import time
import psycopg
from azure.identity import DefaultAzureCredential
HOST = "orders-pg-001.postgres.database.azure.com" # with private access this name resolves to a private IP
DB_NAME = "orders"
DB_USER = "orders-app" # the Entra principal's name, for example a managed identity or a group member
PG_PORT = 6432 # the built-in PgBouncer; use 5432 to connect to PostgreSQL directly
credential = DefaultAzureCredential()
def connect():
"""Open a verified TLS connection. The Entra access token is the password and lasts about an hour."""
token = credential.get_token("https://ossrdbms-aad.database.windows.net/.default").token
return psycopg.connect(
host=HOST, port=PG_PORT, dbname=DB_NAME, user=DB_USER, password=token,
sslmode="verify-full", sslrootcert="system", connect_timeout=5)
def place_order(conn, customer_id, total_cents):
"""Insert one order inside a transaction and return its id."""
with conn.transaction():
row = conn.execute(
"INSERT INTO orders (customer_id, total_cents) VALUES (%s, %s) RETURNING id",
(customer_id, total_cents)).fetchone()
return row[0]
def with_retry(action, delays=(2, 4)):
"""Retry on connection failures, which is what a high availability failover looks like to the app."""
for delay in delays:
try:
with connect() as conn:
return action(conn)
except psycopg.OperationalError:
time.sleep(delay)
with connect() as conn: # last try: let any error reach the caller
return action(conn)
if __name__ == "__main__":
order_id = with_retry(lambda c: place_order(c, 42, 129900))
print(f"Created order {order_id}")
// Program.cs: sign in with Microsoft Entra and insert an order as one atomic batch
// NuGet packages: Npgsql, Azure.Identity
using Azure.Core;
using Azure.Identity;
using Npgsql;
const string host = "orders-pg-001.postgres.database.azure.com";
const string user = "orders-app"; // the Entra principal's name
// The access token is the password; it lasts about an hour, so a long-running app should ask again for each new connection
var credential = new DefaultAzureCredential();
AccessToken token = await credential.GetTokenAsync(
new TokenRequestContext(new[] { "https://ossrdbms-aad.database.windows.net/.default" }));
var builder = new NpgsqlConnectionStringBuilder
{
Host = host,
Port = 6432, // the built-in PgBouncer; 5432 is PostgreSQL itself
Database = "orders",
Username = user,
Password = token.Token,
SslMode = SslMode.VerifyFull, // checks the server certificate against the machine's trusted roots
Timeout = 5
};
await using var dataSource = new NpgsqlDataSourceBuilder(builder.ConnectionString).Build();
// A batch runs inside one implicit transaction: either the order lands or nothing does
await using var batch = dataSource.CreateBatch();
var insert = new NpgsqlBatchCommand("INSERT INTO orders (customer_id, total_cents) VALUES ($1, $2) RETURNING id")
{
Parameters = { new NpgsqlParameter<long> { TypedValue = 42 }, new NpgsqlParameter<int> { TypedValue = 129900 } }
};
batch.BatchCommands.Add(insert);
await using var reader = await batch.ExecuteReaderAsync();
await reader.ReadAsync();
Console.WriteLine($"Created order {reader.GetInt64(0)}");
Best videos to explore
Short walkthrough videos for this service are being prepared. They will appear here and load only when you press play. Until then, follow CloudBrum on YouTube for new videos.
Interview questions
BasicWhat is Azure Database for PostgreSQL?
It’s Microsoft’s managed PostgreSQL service. Today it runs as a flexible server: you choose a version, a compute tier and size, storage and network mode, and Azure runs the machine, patches it, takes backups and handles failover. You still design the schema and manage the roles and queries.
BasicWhat are the compute tiers?
Burstable for development and light, spiky use, General Purpose for most production applications, and Memory Optimized for large working sets and heavy analytics-style queries. The tier and size set the vCores, memory and connection limit, and you can change them later with a restart.
BasicHow long are backups kept, and how do you restore?
Backups are automatic, and you set the retention from 7 to 35 days. Point-in-time restore creates a new server from the backups at a time you choose, and the original server isn’t changed.
IntermediateWhat is the difference between private access and public access?
With private access the server lives on a delegated subnet in your virtual network with a private IP, and clients reach it by a private DNS name, with no public endpoint. With public access it has a public name and a firewall that denies everything until you add rules. The choice is made when the server is created and can’t be flipped on the same server.
IntermediateHow does high availability work, and can you read from the standby?
Azure runs a standby copy, kept in step synchronously, either in another zone (zone-redundant) or in the same zone. If the primary fails, the standby takes over and the server name stays the same. The standby doesn’t answer queries, so for read scaling you add read replicas.
IntermediateHow do applications connect without storing a password?
Turn on Microsoft Entra authentication, add the application’s identity (for example a managed identity) as a database role, and have the app request an access token for the PostgreSQL resource and send it as the password. Tokens last about an hour, so fetch a new one for each connection, and require SSL.
AdvancedYour app opens thousands of short connections and the server hits its limit. What do you do?
Enable the built-in PgBouncer by setting pgbouncer.enabled and point the app at port 6432 so many client connections share a few server connections. Check the pooling mode against how the app uses session features such as prepared statements, shorten idle lifetimes and only then consider a larger compute size.
AdvancedDesign the recovery plan for a Regional outage.
Choose geo-redundant backup when the server is created, or keep a cross-Region read replica, and keep infrastructure code that can rebuild the network, DNS and permissions in the paired Region. State the RPO and RTO, practise promoting a replica or restoring in the other Region, and make the application’s connection settings changeable without a rebuild.
AdvancedHow would you move from the retired Single Server to a flexible server with little downtime?
Use Microsoft’s migration tooling, preferably in its online mode, to copy the data to a new flexible server while the old one stays live. Rebuild networking, because private endpoints and firewall rules differ, test the application and extensions against the new server, then cut over by changing the connection string and finish with a check of roles and sequences.
AdvancedAn extension install fails with an allow-list error. What is happening?
Extensions must be named in the azure.extensions server parameter before CREATE EXTENSION works. Add the extension there, check whether it also needs an entry in shared_preload_libraries (which needs a restart), and then create it. Not every community extension is offered, so check the supported list early in a migration.
Similar or alternative services on other clouds
| Capability | AWS | Azure | Google Cloud |
|---|---|---|---|
| Service | Amazon RDS for PostgreSQL | Azure Database for PostgreSQL (flexible server) | Cloud SQL for PostgreSQL |
| Sizing | Instance classes such as db.m7g.large | Tier plus SKU, such as Burstable or General Purpose Standard_D2ds_v5 | Edition plus a machine tier, such as db-custom-2-7680 |
| Standby for failover | Multi-AZ DB instance (not readable) or Multi-AZ DB cluster (readable) | Zone-redundant or same-zone HA (not readable) | Regional configuration with a standby in another zone |
| Private networking | VPC subnet group and security groups | VNet integration with a delegated subnet, or public access with a firewall | Private IP through private services access, or public IP with authorised networks |
| Sign-in without a password | IAM tokens that last 15 minutes | Entra tokens that last about an hour | IAM database authentication, helped by the Auth Proxy |
| Connection pooling | RDS Proxy (a separate paid component) | PgBouncer included, switched on with a parameter | Bring your own pooler, or managed connection pooling where Google offers it |
| Switching a stopped database off | Stop up to seven days | Stop up to seven days | Stop an instance by setting its activation policy |
| Backups kept | 1 to 35 days | 7 to 35 days | A count of backups from 1 to 365 |
Azure also has separate services for SQL Server (Azure SQL Database and SQL Managed Instance) and for MySQL, and Cosmos DB for non-relational data. If you want PostgreSQL at much larger scale, look at the distributed options inside the service family rather than a bigger single server. Applications that call the database often run on Azure Virtual Machines or Azure Functions.
Did you find this article helpful?
Your answer helps us improve this page for the next reader.
Sources and further reading
CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.
- What is Azure Database for PostgreSQL?Microsoft
- Comparison chart: Flexible Server versus Single ServerMicrosoft
- High availability in Azure Database for PostgreSQL flexible serverMicrosoft
- Networking with private access (virtual network integration)Microsoft
- Use Microsoft Entra ID for authenticationMicrosoft
- Stop and start a flexible serverMicrosoft
- Azure Database for PostgreSQL pricingMicrosoft
- Single Server retirement (28 March 2025) and migrationMicrosoft
- Terraform azurerm: postgresql_flexible_serverHashiCorp
