Azure · lesson 6 of 10
Azure SQL Basics
Provision an Azure SQL Database and logical server, connect with sqlcmd past a firewall error, then restore to a point in time after a bad delete.
By SkillByExample · Updated
Azure SQL Database is a managed, single-database PaaS offering: you provision a logical server for connectivity and firewall rules, then one or more databases under it, and Azure handles patching, high availability, and backups without you managing a VM.
Creating the server and database
az sql server create \
--resource-group learn-rg \
--name learn-sql-srv \
--location eastus \
--admin-user sqladmin \
--admin-password "Tr0ub4dor&3xample!"
$ az sql server create --resource-group learn-rg --name learn-sql-srv --location eastus --admin-user sqladmin --admin-password "Tr0ub4dor&3xample!"
{
"administratorLogin": "sqladmin",
"fullyQualifiedDomainName": "learn-sql-srv.database.windows.net",
"id": "/subscriptions/3b1f9c2a-6d4e-4a7b-9c11-2f5e8a0b7d33/resourceGroups/learn-rg/providers/Microsoft.Sql/servers/learn-sql-srv",
"name": "learn-sql-srv",
"state": "Ready"
}
az sql db create \
--resource-group learn-rg \
--server learn-sql-srv \
--name orders-db \
--service-objective Basic
$ az sql db create --resource-group learn-rg --server learn-sql-srv --name orders-db --service-objective Basic
{
"name": "orders-db",
"status": "Online",
"currentServiceObjectiveName": "Basic",
"maxSizeBytes": 2147483648,
"collation": "SQL_Latin1_General_CP1_CI_AS"
}
Basic tops out at 2 GB and 5 DTUs — enough for this lesson and priced for it, not for
production. fullyQualifiedDomainName is the hostname every client connects to; there’s no
separate concept of a private IP to reach it directly.
Connecting before and after the firewall rule
sqlcmd -S learn-sql-srv.database.windows.net -d orders-db -U sqladmin -P "Tr0ub4dor&3xample!" -Q "SELECT 1"
$ sqlcmd -S learn-sql-srv.database.windows.net -d orders-db -U sqladmin -P "Tr0ub4dor&3xample!" -Q "SELECT 1"
Sqlcmd: Error: Microsoft ODBC Driver 18 for SQL Server : Cannot open server 'learn-sql-srv'
requested by the login. Client with IP address '203.0.113.50' is not allowed to access the
server. To enable access, use the Windows Azure Management Portal or run sp_set_firewall_rule
on the master database to create a firewall rule for this IP address or address range. It may
take up to five minutes for this change to take effect..
Azure SQL blocks every inbound connection by default, and the error usefully includes the IP that got rejected — copy it directly into the fix:
az sql server firewall-rule create \
--resource-group learn-rg \
--server learn-sql-srv \
--name allow-my-ip \
--start-ip-address 203.0.113.50 \
--end-ip-address 203.0.113.50
$ az sql server firewall-rule create --resource-group learn-rg --server learn-sql-srv --name allow-my-ip --start-ip-address 203.0.113.50 --end-ip-address 203.0.113.50
{
"name": "allow-my-ip",
"startIpAddress": "203.0.113.50",
"endIpAddress": "203.0.113.50"
}
sqlcmd -S learn-sql-srv.database.windows.net -d orders-db -U sqladmin -P "Tr0ub4dor&3xample!" -Q "SELECT 1"
$ sqlcmd -S learn-sql-srv.database.windows.net -d orders-db -U sqladmin -P "Tr0ub4dor&3xample!" -Q "SELECT 1"
-----------
1
(1 rows affected)
Loading data and taking a backup checkpoint
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer VARCHAR(50),
amount DECIMAL(10,2)
);
INSERT INTO orders VALUES
(1, 'Ada Lovelace', 25.50),
(2, 'Grace Hopper', 12.00);
$ sqlcmd -S learn-sql-srv.database.windows.net -d orders-db -U sqladmin -P "..." -i create_orders.sql
Changed database context to 'orders-db'.
(2 rows affected)
Azure SQL backs this up automatically — there’s no manual backup command to run. Note the time, since restore is by timestamp, not by backup file:
date -u +"%Y-%m-%dT%H:%M:%SZ"
$ date -u +"%Y-%m-%dT%H:%M:%SZ"
2026-09-12T15:40:00Z
Simulating a mistake, then restoring to before it happened
DELETE FROM orders WHERE order_id = 1;
$ sqlcmd -S learn-sql-srv.database.windows.net -d orders-db -U sqladmin -P "..." -Q "DELETE FROM orders WHERE order_id = 1"
(1 rows affected)
az sql db restore \
--resource-group learn-rg \
--server learn-sql-srv \
--name orders-db \
--dest-name orders-db-restored \
--time "2026-09-12T15:40:00Z"
$ az sql db restore --resource-group learn-rg --server learn-sql-srv --name orders-db --dest-name orders-db-restored --time "2026-09-12T15:40:00Z"
{
"name": "orders-db-restored",
"status": "Online",
"creationDate": "2026-09-12T15:47:12Z",
"restorePointInTime": "2026-09-12T15:40:00Z"
}
SELECT * FROM orders;
$ sqlcmd -S learn-sql-srv.database.windows.net -d orders-db-restored -U sqladmin -P "..." -Q "SELECT * FROM orders"
order_id customer amount
--------- ------------- --------
1 Ada Lovelace 25.50
2 Grace Hopper 12.00
(2 rows affected)
The restore lands in a brand-new database, orders-db-restored, sitting alongside the
original orders-db — which still has the deleted row missing. Recovering the data means
copying the row back or repointing the application, not that the restore silently replaced
anything.
Practice
1. List the automatic restore points currently available for the database.
az sql db list-deleted --resource-group learn-rg --server learn-sql-srv --output table
az sql db show --resource-group learn-rg --server learn-sql-srv --name orders-db --query "earliestRestoreDate"
$ az sql db show --resource-group learn-rg --server learn-sql-srv --name orders-db --query "earliestRestoreDate"
"2026-09-05T15:40:00+00:00"
earliestRestoreDate marks the start of the retention window — any timestamp between it and
now is a valid --time for az sql db restore.
2. Scale the database up to handle more load, then confirm the new tier.
az sql db update --resource-group learn-rg --server learn-sql-srv --name orders-db --service-objective S1
az sql db show --resource-group learn-rg --server learn-sql-srv --name orders-db --query "currentServiceObjectiveName" --output tsv
$ az sql db show --resource-group learn-rg --server learn-sql-srv --name orders-db --query "currentServiceObjectiveName" --output tsv
S1
Scaling a DTU-based tier (Basic, Standard S-tiers, Premium P-tiers) briefly interrupts active connections during the switch but requires no schema or connection-string change.
3. Allow Azure services (like a Function App in the same subscription) to reach the database.
az sql server firewall-rule create \
--resource-group learn-rg \
--server learn-sql-srv \
--name AllowAzureServices \
--start-ip-address 0.0.0.0 \
--end-ip-address 0.0.0.0
$ az sql server firewall-rule create --resource-group learn-rg --server learn-sql-srv --name AllowAzureServices --start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0
{
"name": "AllowAzureServices",
"startIpAddress": "0.0.0.0",
"endIpAddress": "0.0.0.0"
}
0.0.0.0-0.0.0.0 is a special-cased rule Azure recognizes as “allow any Azure-hosted
resource,” not a literal IP range — it doesn’t open the server to the public internet.
4. Delete the restored database once you've recovered what you needed from it.
az sql db delete --resource-group learn-rg --server learn-sql-srv --name orders-db-restored --yes
$ az sql db delete --resource-group learn-rg --server learn-sql-srv --name orders-db-restored --yes
Restored databases bill exactly like any other database while they exist — the point of restoring to a new name is inspection and recovery, not to keep two permanent copies running.
5. Export the database to a .bacpac file for long-term archival outside Azure's automatic backup window.
az sql db export \
--resource-group learn-rg \
--server learn-sql-srv \
--name orders-db \
--admin-user sqladmin \
--admin-password "Tr0ub4dor&3xample!" \
--storage-key-type StorageAccessKey \
--storage-key "<account-key>" \
--storage-uri "https://learnstorage482.blob.core.windows.net/backups/orders-db.bacpac"
$ az sql db export --resource-group learn-rg --server learn-sql-srv --name orders-db ...
{
"requestId": "8f2a1c6d-9e3b-4a17-8c5f-2d6a0b9e7f41",
"status": "Succeeded"
}
Automatic backups only cover the retention window (7-35 days depending on tier); a
.bacpac export is a portable file you control the lifetime of, useful for retention
beyond what Azure keeps automatically or for moving the schema and data elsewhere entirely.
Next: Azure Functions — writing, deploying, and invoking a function, and what changes between a cold start and a warm one.