4. Getting Started
One database, one table, one row — three ways. This page is deliberately throwaway: hard-coded names, a public endpoint, an IP firewall rule, no variables, no state backend, no pipeline. Anything production-shaped lives in Deployment, and copying from this page into a pull request is how you get a review comment.
Everything goes into one resource group so that teardown is a single command.
The task
Create a logical server and one small database, connect, create a table, insert a row, read it back, and delete everything.
Path 1 — Azure Portal
- Search for SQL databases and choose Create.
- On Basics, pick your subscription and a new resource group, name the database
db-demo, and create a new logical server — the server name must be globally unique. Choose Microsoft Entra-only authentication and set yourself as the Entra admin. - Still on Basics, open Configure database and pick General Purpose → Serverless, drop the max vCores to the minimum, and set backup redundancy to Locally-redundant — this is a demo, not a system of record.
- On Networking, set connectivity to Public endpoint and toggle Add current client IP address to yes.
- Create, then open the database's Query editor (preview) blade and sign in with Entra to run SQL in the browser without installing anything.
Portal navigation changes often; the blade names above are stable, the exact button labels are not.
Path 2 — Azure CLI
Copy-pasteable. Change SQL_SERVER to something globally unique before running.
# --- variables -------------------------------------------------------------
RG=rg-sqldemo
LOC=uksouth
SQL_SERVER=sql-demo-$RANDOM$RANDOM # must be globally unique
DB=db-demo
MY_IP=$(curl -s https://api.ipify.org)
ME_UPN=$(az ad signed-in-user show --query userPrincipalName -o tsv)
ME_OID=$(az ad signed-in-user show --query id -o tsv)
# --- throwaway resource group ---------------------------------------------
az group create -n $RG -l $LOC
# --- logical server, Entra-only auth (no SQL password anywhere) ------------
az sql server create \
--name $SQL_SERVER \
--resource-group $RG \
--location $LOC \
--enable-ad-only-auth \
--external-admin-principal-type User \
--external-admin-name "$ME_UPN" \
--external-admin-sid "$ME_OID"
# --- firewall: just my machine --------------------------------------------
az sql server firewall-rule create \
--resource-group $RG --server $SQL_SERVER \
--name allow-my-ip --start-ip-address $MY_IP --end-ip-address $MY_IP
# --- the smallest sensible database: General Purpose serverless ------------
az sql db create \
--resource-group $RG --server $SQL_SERVER --name $DB \
--edition GeneralPurpose \
--compute-model Serverless \
--family Gen5 --capacity 1 \
--min-capacity 0.5 \
--auto-pause-delay 60 \
--backup-storage-redundancy Local
az sql db show -g $RG -s $SQL_SERVER -n $DB -o table
Now connect and do something. sqlcmd with -G uses Entra authentication, so there is still no
password in play:
sqlcmd -S ${SQL_SERVER}.database.windows.net -d $DB -G -Q "
CREATE TABLE dbo.widget (id INT IDENTITY PRIMARY KEY, name NVARCHAR(50) NOT NULL);
INSERT INTO dbo.widget (name) VALUES ('hello');
SELECT id, name FROM dbo.widget;
"
If that first command hangs for 30–60 seconds, the database has auto-paused and is resuming. That is the serverless behaviour from Core Concepts, observed live.
Two more commands worth running once, because they make the abstractions concrete:
# Scale it — watch this take minutes and drop connections at the end
az sql db update -g $RG -s $SQL_SERVER -n $DB --capacity 2
# What has it actually been using?
sqlcmd -S ${SQL_SERVER}.database.windows.net -d $DB -G -Q \
"SELECT TOP 10 end_time, avg_cpu_percent, avg_data_io_percent FROM sys.dm_db_resource_stats ORDER BY end_time DESC;"
PowerShell Az equivalent
Included here because SQL Server shops are overwhelmingly PowerShell-first — this is one of the few
services where the Az module is genuinely the house language rather than an afterthought.
New-AzResourceGroup -Name rg-sqldemo -Location uksouth
New-AzSqlServer -ResourceGroupName rg-sqldemo -ServerName 'sql-demo-uniquename' `
-Location uksouth -EnableActiveDirectoryOnlyAuthentication `
-ExternalAdminName (Get-AzADUser -SignedIn).UserPrincipalName
New-AzSqlDatabase -ResourceGroupName rg-sqldemo -ServerName 'sql-demo-uniquename' `
-DatabaseName 'db-demo' -Edition GeneralPurpose -ComputeModel Serverless `
-ComputeGeneration Gen5 -VCore 1 -MinimumCapacity 0.5
Path 3 — Terraform (minimal)
The smallest thing that stands the same resources up. The parameterised, reviewable version — modules, variables, remote state — is in Deployment.
terraform {
required_providers {
azurerm = { source = "hashicorp/azurerm", version = "~> 4.0" }
}
}
provider "azurerm" {
features {}
}
data "azurerm_client_config" "current" {}
resource "azurerm_resource_group" "demo" {
name = "rg-sqldemo"
location = "uksouth"
}
resource "azurerm_mssql_server" "demo" {
name = "sql-demo-uniquename" # globally unique
resource_group_name = azurerm_resource_group.demo.name
location = azurerm_resource_group.demo.location
version = "12.0" # the only value; it means "Azure SQL", not SQL Server 2014
minimum_tls_version = "1.2"
public_network_access_enabled = true # demo only
azuread_administrator {
login_username = "sqladmins"
object_id = data.azurerm_client_config.current.object_id
tenant_id = data.azurerm_client_config.current.tenant_id
azuread_authentication_only = true # no SQL login, no password
}
}
resource "azurerm_mssql_firewall_rule" "my_ip" {
name = "allow-my-ip"
server_id = azurerm_mssql_server.demo.id
start_ip_address = "203.0.113.10" # your IP
end_ip_address = "203.0.113.10"
}
resource "azurerm_mssql_database" "demo" {
name = "db-demo"
server_id = azurerm_mssql_server.demo.id
sku_name = "GP_S_Gen5_1" # General Purpose, Serverless, Gen5, 1 vCore
min_capacity = 0.5
auto_pause_delay_in_minutes = 60
storage_account_type = "Local" # cheap backup redundancy for a demo
}
output "fqdn" { value = azurerm_mssql_server.demo.fully_qualified_domain_name }
terraform init && terraform apply
Read sku_name carefully — GP_S_Gen5_1 encodes four of the five axes from
Core Concepts in eleven characters: tier (GP), compute model (S for
serverless), hardware family (Gen5), and vCore count (1). BC_Gen5_4 is Business Critical
provisioned with four vCores. HS_Gen5_2 is Hyperscale. Once you can read that string, most Azure
SQL Terraform is readable.
Note also that azurerm_mssql_server.version = "12.0" is not a SQL Server version — it is a legacy
constant meaning "Azure SQL Database", and it is the only accepted value. It confuses everyone once.
[Image Prompt: 2D minimalistic diagram comparing three provisioning paths — Azure Portal, Azure CLI, and Terraform — converging on the same logical SQL server containing one database, with a firewall rule and a Microsoft Entra admin attached to the server, flat design, clean vector art style, white background]
Teardown
Do this now, not later. Deleting the resource group takes the server, the database, the firewall rules, and the backups with it — and it is the cleanest teardown Azure gives you, which is a genuine advantage over per-resource cleanup in AWS.
az group delete -n rg-sqldemo --yes --no-wait
Terraform users: terraform destroy.
One caveat worth knowing now rather than at invoice time: if you had enabled long-term retention backups, deleting the database does not automatically delete those LTR backups, and they keep billing. This demo used the default retention only, so there is nothing left behind — but the general rule is in Deployment.
What you should be able to do now
Stand up a working Azure SQL database in under five minutes, read a sku_name string correctly, and
watch a serverless database pause and resume — which makes every later discussion of cost concrete
rather than theoretical.
Next: Deployment →
← Back to the Azure SQL Database overview · ← Previous: Architecture