Deployment guide

SQL Server 2025 Standard on Ubuntu 24.04

Overview

SQL Server 2025 is Microsoft's relational database engine. The Standard edition suits production departmental and small-to-midsize workloads. It runs the full database engine with Microsoft's Standard edition limits on cores and buffer-pool memory (see Microsoft's SQL Server 2025 editions and features). It reports itself as Standard Edition (64-bit). SQL Server 2025 adds a native vector data type and vector indexes, a native JSON data type, regular expressions in T-SQL and Query Store on by default.

This SecureAnyCloud AMI runs SQL Server 2025 Standard on Ubuntu 24.04 on Amazon EC2. It is one version of the SecureAnyCloud Microsoft SQL Server on Ubuntu listing on AWS Marketplace, and you pick it as the software version when you subscribe and launch.

Bring your own licence. No SQL Server licence is included with this AMI. You must hold SQL Server core licences for it (see Licensing).

What you get:

  • No shared or default 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 AMI. On your instance's first boot, mssql-firstboot.service generates an sa password on the instance and runs Microsoft's own unattended setup with it. It then writes the password to /root/mssql-credentials.txt (root-only). No two instances share a password, a certificate or an instance identity.
  • 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 instance's own TLS key and self-signed certificate. SQL Server forces encryption (TLS 1.2) for every client, even one that does not ask for it.
  • Localhost only. SQL Server listens on 127.0.0.1:1433, and the security group opens SSH only. You reach the database through an SSH tunnel, or by changing the listen address yourself (see Connect from other hosts).
  • Metadata service blocked. SQL Server and its first-boot service cannot reach the EC2 instance metadata service, and the AMI requires IMDSv2.
  • Hardened defaults. Telemetry (Microsoft's customer feedback program) and SQL Server Agent are off. xp_cmdshell, OLE Automation, CLR, ad hoc distributed queries and the remote admin connection are all disabled.
  • Fully patched base. Ubuntu 24.04 LTS is patched at build time, with unattended security upgrades switched on.
  • What is on the image: SQL Server 2025 Standard Edition 17.0.5015.4 (CU9 with the 2026-10-13 security update, KB5126967), 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 AWS Systems Manager agent are included.
  • Defaults: the ubuntu user, x86_64 architecture and a recommended instance type of m5.large.

Licensing

This version is Bring Your Own License (BYOL). No SQL Server licence is included with the AMI and none is sold with it. The listing's hourly charge covers SecureAnyCloud's hardening and first-boot setup only. Before you run it, you must hold the right Microsoft licences:

  • SQL Server 2025 Standard core licences for the instance's vCPUs, under Microsoft's per-core licensing rules.
  • Software Assurance with License Mobility, which lets you run those licences on shared-tenancy Amazon EC2 instances. Without License Mobility, run on Amazon EC2 Dedicated Hosts as Microsoft's Product Terms allow.

Your instance accepts the Microsoft Software License Terms on first boot and sets the edition with MSSQL_PID=Standard. There is no product key to enter. Direct licensing questions to Microsoft or your Microsoft licensing partner.

If you do not hold a SQL Server licence, the Express version of this listing is free within its limits. The Developer version is free for development and testing only, never production.

Prerequisites

Before you launch, make sure you have:

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
  • A security group that allows TCP 22 (SSH) from your admin network. Do not open port 1433, because SQL Server listens on the loopback address only.
  • SQL Server 2025 Standard licences with Software Assurance and License Mobility (or a Dedicated Host), as described under Licensing.
1

Launch the instance

In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick SQL Server 2025 Standard on Ubuntu 24.04 as the software version, select your Region and choose Launch through EC2. Choose m5.large or larger, your key pair and a security group as described above. SQL Server needs at least 2 GB of memory.

To launch with the AWS CLI instead, run the command below and replace the values in angle brackets with your own:

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=sql-server-standard}]'

On a new instance, first boot takes about five minutes. Amazon EBS loads the AMI's blocks from its snapshot the first time they are read, and SQL Server's setup reads 1.4 GB of program files. Until first boot finishes, systemctl is-active mssql-firstboot reports activating and /root/mssql-credentials.txt does not yet hold the real password. Later boots start SQL Server in seconds.

2

Connect to your instance

For SQL Server 2025 Standard on Ubuntu 24.04, the SSH user is ubuntu. Connect with your key pair:

ssh -i <your-key.pem> ubuntu@<public-ip>
3

Check the service

Confirm that the first-boot service and SQL Server both report active:

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

Check what is listening. SQL Server listens on the loopback address only. Port 1433 is the database port. Port 1431 is a SQL Server port used only on the instance. Port 1434 is the local dedicated administrator connection (DAC), the emergency connection a sysadmin can use from the instance itself when SQL Server stops responding. Remote DAC is off, and only SSH listens on the network.

sudo ss -Htlnp | awk '{print $4, $6}' | sed 's/,pid=[0-9]*,fd=[0-9]*//g' | sort -u
0.0.0.0:22 users:(("sshd"),("systemd")) 127.0.0.1:1431 users:(("sqlservr")) 127.0.0.1:1433 users:(("sqlservr")) 127.0.0.1:1434 users:(("sqlservr")) 127.0.0.53%lo:53 users:(("systemd-resolve")) 127.0.0.54:53 users:(("systemd-resolve")) [::1]:1431 users:(("sqlservr")) [::1]:1434 users:(("sqlservr")) [::]:22 users:(("sshd"),("systemd"))
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 900 Oct 20 04:09 /root/mssql-credentials.txt SA_USER= SA_PASSWORD= <set-at-first-boot>= 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 instance.

Never pass the password to sqlcmd with -P, because 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), and the blocks use the full path.

5

Connect with sqlcmd

Run sqlcmd on the instance. The -C flag tells it to trust the instance's self-signed certificate. Step 6 shows how to pin the certificate 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 ---------------------------------------- -------------------- ---------- -------------- Standard Edition (64-bit) 17.0.5015.4 CU9 2

An engine_edition of 2 is Standard edition.

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. Run:

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 instance's own, named after its hostname. Inspect it with the command below. The sample output is from a different instance, so your names and fingerprint will differ.

openssl x509 -in /etc/ssl/mssql/mssql.pem -noout -subject -enddate -ext subjectAltName -fingerprint -sha256
subject=CN = ip-172-31-93-36 notAfter=Oct 17 04:08:52 2036 GMT X509v3 Subject Alternative Name: DNS:ip-172-31-93-36, DNS:localhost, IP Address:127.0.0.1 sha256 Fingerprint=BE:6E:09:B4:D5:3A:DA:64:36:BA:1A:7B:07:80:8E:BC:16:FC:B0:E0:39:F9:DE:A6:88:C7:A9:37:61:72:3D:48

The same fingerprint is in /root/mssql-credentials.txt as TLS_CERT_SHA256. To verify the server instead of trusting it blindly, copy /etc/ssl/mssql/mssql.pem to your client and add it to the client's trusted certificates. This is the public certificate, so never copy mssql.key. In tools that support it, you can pin the fingerprint instead. Because the certificate names localhost and 127.0.0.1, verification also passes through the SSH tunnel in Step 8.

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 2025 Standard'');'); SELECT id, body FROM demo.dbo.notes; DROP DATABASE demo;"
id body -- ---- 1 hello from SQL Server 2025 Standard

For an application, create a dedicated login and database instead of using sa. Run the statements below in an interactive sqlcmd session (/opt/mssql-tools18/bin/sqlcmd -S 127.0.0.1 -U sa -C) and choose 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
8

Connect from other hosts

The safest way to use SQL Server Management Studio, Azure Data Studio, VS Code or an application on your workstation is an SSH tunnel, which keeps port 1433 closed to the network. Open the tunnel:

ssh -i <your-key.pem> -N -L 1433:127.0.0.1:1433 ubuntu@<public-ip>

Then connect your client to 127.0.0.1,1433. Use SQL Server authentication as sa and set encryption to Mandatory (or Strict). Either trust the server certificate or install mssql.pem as a trusted certificate (Step 6).

If applications on other hosts in your VPC must connect directly, open the listen address and restart SQL Server. Then allow TCP 1433 in the security group from those hosts' CIDRs only, never from 0.0.0.0/0:

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

Encryption stays forced. The certificate names the instance's hostname, localhost and 127.0.0.1. Clients that connect by another name must trust the certificate, or use a certificate you issue for that name (mssql-conf set network.tlscert and network.tlskey, then restart).

Security details

Check the hardening settings as SQL Server reports them:

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(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"
name value_in_use ---- ------------ Ad Hoc Distributed Queries 0 clr enabled 0 Ole Automation Procedures 0 remote admin connections 0 xp_cmdshell 0

Check the 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
ipaddress : 127.0.0.1 tcpport : 1433 tlscert : /etc/ssl/mssql/mssql.pem tlskey : /etc/ssl/mssql/mssql.key tlsprotocols : 1.2 forceencryption : 1 customerfeedback : false IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32
  • First boot (/usr/local/sbin/mssql-firstboot.sh) creates the TLS key and certificate. It generates the sa password into a root-only file in memory and runs mssql-conf -n setup accept-eula with MSSQL_PID=Standard, passing the password in the environment (never on a command line). It then checks the edition and build, that a wrong sa password is refused, that the connection is encrypted, that port 1433 serves the instance's certificate and listens on localhost only, and that the metadata service is unreachable. Only after these checks does it write the credentials file. Its log is available with journalctl -u mssql-firstboot.
  • Start gate. mssql-server.service has a drop-in, /etc/systemd/system/mssql-server.service.d/50-sac.conf. It blocks the metadata service and refuses to start before first boot has written /var/lib/sac/data/mssql-ready.
  • Dedicated administrator connection (DAC). Standard edition opens the DAC, SQL Server's emergency sysadmin connection, on 127.0.0.1:1434 and [::1]:1434 only. remote admin connections is 0, so the DAC cannot be reached from another host, and the security group never opens port 1434. To use it, connect from the instance itself with sqlcmd -S 127.0.0.1,1434 -U sa -C. Only one DAC session is allowed at a time.
  • Data and logs live under /var/opt/mssql (data/ and log/errorlog). The configuration file is /var/opt/mssql/mssql.conf.

The DAC listens locally only. The errorlog records it, and a connection to port 1434 on the instance's private address is refused. Verify both:

sudo grep -a 'Dedicated admin' /var/opt/mssql/log/errorlog | cut -c24- timeout 3 bash -c "exec 3<>/dev/tcp/$(hostname -I | awk '{print $1}')/1434" 2>/dev/null && echo open || echo refused
Server Dedicated admin connection support was established for listening locally on port 1434. refused

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 instance, for example to Amazon S3:

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

Standard edition supports backup compression (WITH COMPRESSION) and encrypted backups. Take EBS snapshots of the volume as a second layer of protection.

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 that file current.

Memory. By default, SQL Server on Linux uses up to 80% of the instance's memory, and Standard edition caps the buffer pool at Microsoft's Standard edition limit. 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. Standard 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. Standard is licensed per core. If you move to an instance type with more vCPUs, make sure your SQL Server core licences cover it. SQL Server uses only the cores its edition allows, and the errorlog line using N logical processors based on SQL Server licensing shows the count.

Support

SecureAnyCloud provides 24/7 technical support for this image by email and live chat at sales@secureanycloud.com. Direct SQL Server licensing questions to Microsoft or your licensing partner. Other versions of this listing are described in the SQL Server on Ubuntu guide.

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

Deploy on AWS

Launch SQL Server 2025 Standard on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS