Ss
Databases Azure

SQL Server 2022 Web on Ubuntu 22.04 on Azure User Guide

| Product: SQL Server 2022 Web on Ubuntu 22.04 LTS on Azure

Videos

Overview: SQL Server 2022 Web on Azure: overview (watch on YouTube)
Launch and log in: SQL Server 2022 Web on Azure: launch and log in (watch on YouTube)
Deep Dive: SQL Server 2022 Web on Azure: deep dive (watch on YouTube)

Overview

This guide covers deploying and using SQL Server 2022 Web on Ubuntu 22.04 from cloudimg on Microsoft Azure.

SQL Server 2022 is Microsoft's relational database engine. Web is its edition for public, Internet-accessible web pages, sites, applications and services: the full database engine within Microsoft's Web edition limits (the lesser of 4 sockets or 16 cores, and 64 GB of buffer-pool memory; see Microsoft's SQL Server 2022 editions and features). It reports itself as Web Edition (64-bit). SQL Server 2022 adds ledger tables, contained availability groups, Query Store hints, parameter-sensitive plan optimization and new T-SQL functions such as JSON_OBJECT and JSON_ARRAY.

SPLA licensing. No SQL Server licence is included in the price of this image: Web edition is licensed only through the Microsoft Services Provider License Agreement (see Licensing).

What the cloudimg image adds:

  • No shared, default or temporary password. The image ships SQL Server installed but not set up: there is no master database, no sa password and no machine key in the image. On your VM's first boot, mssql-firstboot.service generates a 32-character sa password on the VM and runs Microsoft's own unattended setup with it, then writes it to /root/mssql-credentials.txt (root only). No two VMs share a password, a certificate or an instance identity.
  • Port 1433 opens last. First boot sets SQL Server up on the loopback address only and checks it (edition, password, encryption, certificate) before it opens port 1433 on the VM's network interfaces. SQL Server never listens on the network with any password but your VM's own.
  • Fail closed. SQL Server refuses to start until first boot has finished. If first boot cannot complete, SQL Server stays stopped and the next boot tries again.
  • TLS on every connection. First boot creates the VM's own TLS key and self-signed certificate, and SQL Server forces encryption (TLS 1.2) for every client, even one that does not ask for it.
  • One login. sa is the only SQL login, with the password policy enforced. No default database or extra login is created.
  • No metadata access for the database. SQL Server and its first-boot service are blocked from the Azure Instance Metadata Service and the Azure wire server.
  • Telemetry off (Microsoft's customer feedback program), SQL Server Agent off, and xp_cmdshell, OLE Automation, CLR, ad hoc distributed queries and the remote admin connection all disabled.
  • Fully patched Ubuntu 22.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: SQL Server 2022 Web Edition 16.0.4305.5 (CU27 with the 2026-10-13 security update, KB5126934), mssql-tools18 (sqlcmd, bcp) and the Microsoft ODBC Driver 18 for SQL Server 18.7.1.1, all from Microsoft's official packages.microsoft.com repositories with the signing key pinned; cloud-init and the Azure Linux Agent.

Default user: the admin user you choose (examples use azureuser) · Architecture: x64, Gen2 · Recommended size: Standard_D4s_v3 or larger

Licensing

SQL Server 2022 Web edition is licensed only through the Microsoft Services Provider License Agreement (SPLA), for public and Internet-accessible web pages, websites, web applications and web services. No SQL Server licence is included in this image and none is sold with it: the cloudimg charge covers the image, its hardening, first-boot setup, maintenance and support. You need a SPLA agreement that covers the VM's cores, and the workload must be one Web edition is licensed for.

Your VM accepts the Microsoft Software License Terms on first boot and sets the edition with MSSQL_PID=Web; there is no product key to enter. Licensing questions go to Microsoft or your SPLA reseller.

Prerequisites

  • An Azure subscription and a subscription to this offer in Azure Marketplace.
  • An SSH public key or a password for the VM's admin user.
  • A Microsoft SPLA agreement covering SQL Server 2022 Web for the VM's cores, as described under Licensing.
  • A network security group that allows TCP 22 (SSH) from your admin network. Open TCP 1433 only if clients on other hosts must connect directly, and only from their addresses (Step 8).

Step 1: Deploy the virtual machine from the Azure portal

In Azure Marketplace search for SQL Server 2022 Web, select the cloudimg offer and click Create.

On the Basics tab choose your subscription, resource group and region, name the VM, choose Standard_D4s_v3 or larger (SQL Server needs at least 2 GB of memory) and set the administrator account. Under Inbound port rules allow SSH (22) only.

On the Disks tab choose Standard SSD or Premium SSD. SQL Server data lives in /var/opt/mssql/data on the OS disk.

On the Networking tab keep or select a network security group that allows SSH from your admin network. Click Review + create, then Create.

Step 2: Deploy the virtual machine from the Azure CLI

Accept the Marketplace terms once per subscription, then create the VM (replace the values in angle brackets):

az vm image terms accept --urn cloudimg1647283583153:mssql-2022-web-ubuntu-22-04:default:latest

az vm create \
  --resource-group <your-resource-group> \
  --name sql-web-01 \
  --image cloudimg1647283583153:mssql-2022-web-ubuntu-22-04:default:latest \
  --size Standard_D4s_v3 \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_rsa.pub \
  --nsg-rule SSH

First boot takes two to three minutes: SQL Server's setup creates the system databases. Until it finishes, systemctl is-active mssql-firstboot reports activating and /root/mssql-credentials.txt holds a placeholder. Later boots start SQL Server in seconds.

Step 3: Connect and check the service

ssh azureuser@<vm-public-ip>

The first-boot service and SQL Server both report active:

systemctl is-active mssql-firstboot mssql-server
active
active

Check what is listening. 1433 is the database port, open on every interface (IPv4 0.0.0.0 and the dual-stack *). 1431 is an internal SQL Server port and 1434 is the local dedicated administrator connection (DAC), the emergency connection a sysadmin can use from the VM itself when SQL Server stops responding; both stay on the loopback address. Remote DAC is off.

sudo ss -Htlnp | awk '{print $4, $6}' | sed 's/,pid=[0-9]*,fd=[0-9]*//g' | sort -u
*:1433 users:(("sqlservr"))
0.0.0.0:1433 users:(("sqlservr"))
0.0.0.0:22 users:(("sshd"))
127.0.0.1:1431 users:(("sqlservr"))
127.0.0.1:1434 users:(("sqlservr"))
127.0.0.53%lo:53 users:(("systemd-resolve"))
[::1]:1431 users:(("sqlservr"))
[::1]:1434 users:(("sqlservr"))
[::]:22 users:(("sshd"))

SQL Server first-boot service and listeners

Step 4: Get your sa password

The credentials file is readable only by root. List the setting names it holds:

sudo ls -l /root/mssql-credentials.txt
sudo grep -oE '^[A-Z_0-9]+=' /root/mssql-credentials.txt
-rw------- 1 root root 1170 Oct 23 15:24 /root/mssql-credentials.txt
SA_USER=
SA_PASSWORD=
SQL_ENDPOINT=
SQL_ENDPOINT_PRIVATE=
SQL_EDITION=
TLS_CERT=
TLS_CERT_SHA256=

Read the whole file with sudo cat /root/mssql-credentials.txt and store the password in your password manager. It is unique to this VM.

Never pass the password to sqlcmd with -P: it would land in your shell history and the process list. sqlcmd reads it from the SQLCMDPASSWORD environment variable instead. Load it once per shell:

export SQLCMDPASSWORD="$(sudo awk -F= '/^SA_PASSWORD=/{print $2}' /root/mssql-credentials.txt)"

The blocks below repeat that line so that each one works on its own. sqlcmd is on the PATH of every login shell (/opt/mssql-tools18/bin); the blocks use the full path.

The credentials file and the sa login

Step 5: Connect with sqlcmd

-C tells sqlcmd to trust the VM's self-signed certificate (Step 6 shows how to verify it instead).

export SQLCMDPASSWORD="$(sudo awk -F= '/^SA_PASSWORD=/{print $2}' /root/mssql-credentials.txt)"
/opt/mssql-tools18/bin/sqlcmd -S 127.0.0.1 -U sa -C -Q "SET NOCOUNT ON; SELECT CAST(SERVERPROPERTY('Edition') AS nvarchar(40)) AS edition, CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(20)) AS version, CAST(SERVERPROPERTY('ProductUpdateLevel') AS nvarchar(10)) AS cu, CAST(SERVERPROPERTY('EngineEdition') AS int) AS engine_edition"
edition                                  version              cu         engine_edition
---------------------------------------- -------------------- ---------- --------------
Web Edition (64-bit)                     16.0.4305.5          CU27                    2

engine_edition 2 is the Standard engine, which Web edition runs.

Web Edition, CU27, encrypted session

Step 6: Confirm the connection is encrypted

SQL Server forces encryption, so even a client that asks only for optional encryption (-No) gets an encrypted session:

export SQLCMDPASSWORD="$(sudo awk -F= '/^SA_PASSWORD=/{print $2}' /root/mssql-credentials.txt)"
/opt/mssql-tools18/bin/sqlcmd -S 127.0.0.1 -U sa -C -No -Q "SET NOCOUNT ON; SELECT encrypt_option, protocol_type, auth_scheme FROM sys.dm_exec_connections WHERE session_id = @@SPID"
encrypt_option                           protocol_type                            auth_scheme
---------------------------------------- ---------------------------------------- ----------------------------------------
TRUE                                     TSQL                                     SQL

The certificate is this VM's own, named after its hostname (the VM name) and addresses. On a test VM:

openssl x509 -in /etc/ssl/mssql/mssql.pem -noout -subject -enddate -ext subjectAltName -fingerprint -sha256
subject=CN = mssql-web-2204-simA-10231437-c1a604
notAfter=Oct 20 15:21:18 2036 GMT
X509v3 Subject Alternative Name:
    DNS:mssql-web-2204-simA-10231437-c1a604, DNS:localhost, IP Address:127.0.0.1, IP Address:10.0.0.12
sha256 Fingerprint=52:A6:F6:A8:99:AC:90:3F:8D:5D:29:D4:D3:77:CF:EE:91:F3:DC:FB:10:82:CC:A7:29:47:37:B1:CF:5C:ED:97

The same fingerprint is in /root/mssql-credentials.txt as TLS_CERT_SHA256. To verify the server instead of trusting it blindly, make the certificate the client's trusted certificate and drop -C. A client without it refuses the self-signed certificate; with it, full verification passes:

export SQLCMDPASSWORD="$(sudo awk -F= '/^SA_PASSWORD=/{print $2}' /root/mssql-credentials.txt)"
SSL_CERT_FILE=/etc/ssl/mssql/mssql.pem /opt/mssql-tools18/bin/sqlcmd -S 127.0.0.1 -U sa -F "$(hostname)" -h -1 -Q "SET NOCOUNT ON; SELECT N'verified: ' + CAST(SERVERPROPERTY('ServerName') AS nvarchar(64))"
verified: mssql-web-2204-simA-10231437-c1a604

On your workstation, copy /etc/ssl/mssql/mssql.pem (the public certificate, never mssql.key) and add it to the client's trusted certificates, or pin the fingerprint in tools that support it.

Step 7: Run SQL

Create a database, write a row, read it back and drop the database:

export SQLCMDPASSWORD="$(sudo awk -F= '/^SA_PASSWORD=/{print $2}' /root/mssql-credentials.txt)"
/opt/mssql-tools18/bin/sqlcmd -S 127.0.0.1 -U sa -C -W -Q "SET NOCOUNT ON; CREATE DATABASE demo; EXEC('USE demo; CREATE TABLE dbo.notes (id INT IDENTITY PRIMARY KEY, body NVARCHAR(200) NOT NULL); INSERT INTO dbo.notes (body) VALUES (N''hello from SQL Server 2022 Web'');'); SELECT id, body FROM demo.dbo.notes; DROP DATABASE demo;"
id body
-- ----
1 hello from SQL Server 2022 Web

Round trip as sa, a wrong password refused

For an application, create its own login and database instead of using sa. Run this in an interactive sqlcmd session (/opt/mssql-tools18/bin/sqlcmd -S 127.0.0.1 -U sa -C), choosing your own strong password:

CREATE DATABASE appdb;
GO
CREATE LOGIN appuser WITH PASSWORD = N'<a-strong-password>', CHECK_POLICY = ON;
GO
USE appdb;
CREATE USER appuser FOR LOGIN appuser;
ALTER ROLE db_owner ADD MEMBER appuser;
GO

Step 8: Connect from other hosts

SQL Server listens on port 1433 on the VM's network interfaces with encryption forced, so a client on another host can connect once your network security group allows it. Allow TCP 1433 only from the addresses that need it, never from Internet or *:

az network nsg rule create --resource-group <your-resource-group> --nsg-name <your-vm-nsg> \
  --name allow-sql-from-app --priority 310 --access Allow --protocol Tcp --direction Inbound \
  --source-address-prefixes <client-ip-or-cidr> --destination-port-ranges 1433

From the VM itself you can confirm that the private address accepts an encrypted session:

export SQLCMDPASSWORD="$(sudo awk -F= '/^SA_PASSWORD=/{print $2}' /root/mssql-credentials.txt)"
/opt/mssql-tools18/bin/sqlcmd -S "$(hostname -I | awk '{print $1}'),1433" -U sa -C -No -h -1 -Q "SET NOCOUNT ON; SELECT CAST(client_net_address AS varchar(20)) + ' encrypted=' + CAST(encrypt_option AS varchar(5)) FROM sys.dm_exec_connections WHERE session_id = @@SPID"
10.0.0.12 encrypted=TRUE

Connect SQL Server Management Studio, Azure Data Studio, VS Code or your application to <vm-ip>,1433 with SQL Server authentication as sa (or your application login), encryption Mandatory, and either trust the server certificate or install mssql.pem as a trusted certificate (Step 6). The certificate names the VM's hostname, localhost and its private address; clients connecting by another name need to trust the certificate or use a certificate you issue for that name (mssql-conf set network.tlscert and network.tlskey, then restart).

If you prefer to keep 1433 closed to the network entirely, bind SQL Server to the loopback address and use an SSH tunnel (ssh -N -L 1433:127.0.0.1:1433 azureuser@<vm-public-ip>):

sudo /opt/mssql/bin/mssql-conf set network.ipaddress 127.0.0.1
sudo systemctl restart mssql-server

Security details

Logins and hardening settings, as SQL Server reports them. A wrong password is refused:

export SQLCMDPASSWORD="$(sudo awk -F= '/^SA_PASSWORD=/{print $2}' /root/mssql-credentials.txt)"
/opt/mssql-tools18/bin/sqlcmd -S 127.0.0.1 -U sa -C -W -Q "SET NOCOUNT ON; SELECT name, CAST(is_policy_checked AS int) AS policy_checked, CAST(is_disabled AS int) AS disabled FROM sys.sql_logins WHERE name NOT LIKE N'##%' ORDER BY name"
/opt/mssql-tools18/bin/sqlcmd -S 127.0.0.1 -U sa -C -W -Q "SET NOCOUNT ON; SELECT name, CAST(value_in_use AS int) AS value_in_use FROM sys.configurations WHERE name IN (N'xp_cmdshell', N'clr enabled', N'Ole Automation Procedures', N'Ad Hoc Distributed Queries', N'remote admin connections') ORDER BY name"
SQLCMDPASSWORD=not-the-password /opt/mssql-tools18/bin/sqlcmd -S 127.0.0.1 -U sa -C -Q "SELECT 1" 2>&1 | head -1 || true
name policy_checked disabled
---- -------------- --------
sa 1 0
name value_in_use
---- ------------
Ad Hoc Distributed Queries 0
clr enabled 0
Ole Automation Procedures 0
remote admin connections 0
xp_cmdshell 0
Sqlcmd: Error: Microsoft ODBC Driver 18 for SQL Server : Login failed for user 'sa'..

Network, TLS and telemetry settings, and the metadata block on both services:

sudo /opt/mssql/bin/mssql-conf get network
sudo /opt/mssql/bin/mssql-conf get telemetry customerfeedback
systemctl show -p IPAddressDeny mssql-server mssql-firstboot
tcpport : 1433
tlscert : /etc/ssl/mssql/mssql.pem
tlskey : /etc/ssl/mssql/mssql.key
tlsprotocols : 1.2
forceencryption : 1
customerfeedback : false
IPAddressDeny=169.254.169.254/32 168.63.129.16/32

IPAddressDeny=169.254.169.254/32 168.63.129.16/32
  • First boot (/usr/local/sbin/mssql-firstboot.sh) creates the TLS key and certificate, generates the sa password into a root-only file in memory, and runs mssql-conf -n setup accept-eula with MSSQL_PID=Web, passing the password in the environment (never on a command line). With SQL Server still on the loopback address it checks the edition and build, that a wrong sa password is refused, that the connection is encrypted, that port 1433 serves the VM's own certificate and that the metadata service is unreachable. Only then does it open port 1433 on the network, check login, refusal and the certificate again over the VM's private address, and write the credentials file. Its log is journalctl -u mssql-firstboot.
  • Start gate. mssql-server.service has a drop-in, /etc/systemd/system/mssql-server.service.d/50-cloudimg.conf, that blocks the metadata service and refuses to start before first boot has written /var/lib/cloudimg/mssql-ready.
  • SSH. /etc/ssh/sshd_config.d/00-cloudimg.conf turns off root login, empty passwords and X11 forwarding. Password or key login for your admin user follows the choice you made when you created the VM.
  • Data and logs live under /var/opt/mssql (data/, log/errorlog); configuration is /var/opt/mssql/mssql.conf.

Maintenance

Updates. Ubuntu security updates install automatically. SQL Server cumulative and security updates come from Microsoft's repository, which the image already trusts; install them when you are ready:

sudo apt-get update
sudo apt-get install --only-upgrade mssql-server mssql-tools18 msodbcsql18

Backups. Back up to a local file, then copy it off the VM (for example to Azure Blob Storage):

sqlcmd -S 127.0.0.1 -U sa -C -Q "BACKUP DATABASE appdb TO DISK = N'/var/opt/mssql/data/appdb.bak' WITH CHECKSUM"

Web edition does not support backup compression; back up uncompressed and compress the copy if you need to. Take Azure disk snapshots as a second layer.

Change the sa password. Connect as sa and run ALTER LOGIN sa WITH PASSWORD = N'<new-password>';, then update /root/mssql-credentials.txt if you keep it.

Memory. Web edition uses at most 64 GB for the buffer pool; by default SQL Server on Linux uses up to 80% of the VM's memory. To leave more for other software, set a limit and restart, for example sudo /opt/mssql/bin/mssql-conf set memory.memorylimitmb 4096 then sudo systemctl restart mssql-server.

SQL Server Agent. Web edition includes SQL Server Agent for scheduled jobs. It ships turned off; turn it on when you need it:

sudo /opt/mssql/bin/mssql-conf set sqlagent.enabled true
sudo systemctl restart mssql-server

Licences when you resize. Web is licensed per core. If you move to a VM size with more vCPUs, make sure your SQL Server licences cover it; SQL Server uses only the cores its edition allows.

Support

cloudimg provides 24/7 technical support for this image by email and live chat: support@cloudimg.co.uk. SQL Server licensing questions go to Microsoft.

Microsoft, Azure and SQL Server are trademarks of the Microsoft group of companies. Ubuntu is a registered trademark of Canonical Ltd. cloudimg is not affiliated with or endorsed by Microsoft or Canonical.