SQL Server on Linux – installation – part 1


For some reasons I have never ever dig into SQL Server mainly because the only possible operating system was Windows. But starting with SQL Server 2017 Microsoft has started to embrace Linux and has released SQL Server on Linux with a limited set of functionalities but release after release this list is collapsing.

One cool thing that I really appreciate with SQL Server is that you get almost all cool features (compression, in-memory, security) in enterprise edition without being obliged to buy an option (like with Oracle Enterprise edition options). And for most of them they are even accessible with the standard edition like Columnstore and In-Memory Database: In-Memory OLTP.

We have even recently discovered (yes we are late) that with SQL Server Developer edition we can even have a free edition to be used in Q&A, Test and Dev only and only if you do not import into your production figures.

Microsoft is also much more flexible than Oracle on virtualization (not too hard you would say). In short you can licensed only a single virtual Machine for SQL Server or with SQL Server Enterprise edition you can license your physical host and apply for maximum virtualization (unlimited number of virtual machine running SQL Server).

According to Microsoft 30-40% of their SQL Server customers are doing Linux, most probably with the help of cloud vendors.

This first blog post is a raw installation of SQL Server 15.0.4178.1-3 on Red Hat Enterprise Linux Server release 7.9 (Maipo) but more to come…

SQL Server on Linux installation

Configure the Linux repository with:

[root@server1 ~]# cd /etc/yum.repos.d
[root@server1 yum.repos.d]# wget https://packages.microsoft.com/config/rhel/7/mssql-server-2019.repo
--2021-11-10 11:54:38--  https://packages.microsoft.com/config/rhel/7/mssql-server-2019.repo
Resolving proxy.domain.com (proxy.domain.com)...
Connecting to proxy.domain.com (proxy.domain.com)||:8080... connected.
Proxy request sent, awaiting response... 200 OK
Length: 231 [application/octet-stream]
Saving to: ‘mssql-server-2019.repo’
100%[======================================================================>] 231         --.-K/s   in 0s
2021-11-10 11:54:39 (39.3 MB/s) - ‘mssql-server-2019.repo’ saved [231/231]
[root@server1 yum.repos.d]# ll mssql-server-2019.repo
-rw-r--r-- 1 root root 231 Nov 10 11:26 mssql-server-2019.repo
[root@server1 yum.repos.d]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.9 (Maipo)

Once the repository is configured the installation is as simple as:

[root@server1 ~]# dnf install -y mssql-server

Use the suggested command to configure SQL Server for Linux. My advice is to choose the Developer edition that has all Enterprise feature but that must not be used in production (must also not contains any production figures for testing):

[root@server1 ~]# /opt/mssql/bin/mssql-conf setup
usermod: no changes
Choose an edition of SQL Server:
  1) Evaluation (free, no production use rights, 180-day limit)
  2) Developer (free, no production use rights)
  3) Express (free)
  4) Web (PAID)
  5) Standard (PAID)
  6) Enterprise (PAID) - CPU Core utilization restricted to 20 physical/40 hyperthreaded
  7) Enterprise Core (PAID) - CPU Core utilization up to Operating System Maximum
  8) I bought a license through a retail sales channel and have a product key to enter.
Details about editions can be found at
Use of PAID editions of this software requires separate licensing through a
Microsoft Volume Licensing program.
By choosing a PAID edition, you are verifying that you have the appropriate
number of licenses in place to install and run this software.
Enter your edition(1-8): 2
The license terms for this product can be found in
/usr/share/doc/mssql-server or downloaded from:
The privacy statement can be viewed at:
Do you accept the license terms? [Yes/No]:Yes
Enter the SQL Server system administrator password:
Confirm the SQL Server system administrator password:
Configuring SQL Server...
ForceFlush is enabled for this instance.
ForceFlush feature is enabled for log durability.
Created symlink from /etc/systemd/system/multi-user.target.wants/mssql-server.service to /usr/lib/systemd/system/mssql-server.service.
Setup has completed successfully. SQL Server is now starting.

I have decided to create a dedicated Veritas FileSystem to store all my database file (much better than using the system disks):

[root@server1 ~]# vxassist -g vgperp maxsize
Maximum volume size: 136239104 (66523Mb)
[root@server1 ~]# vxassist -g vgperp make lvol4 1g
[root@server1 ~]# vxassist -g vgperp maxsize
Maximum volume size: 134141952 (65499Mb)
[root@server1 ~]#  mkfs -t vxfs -o bsize=8192,largefiles /dev/vx/rdsk/vgperp/lvol4
    version 15 layout
    2097152 sectors, 131072 blocks of size 8192, log size 2048 blocks
    rcq size 128 blocks
    largefiles supported
    maxlink supported
    WORM not supported
[root@server1 ~]# grep mssql /etc/fstab
/dev/vx/dsk/vgperp/lvol4        /mssql                                          vxfs defaults,_netdev 1 2
[root@server1 ~]# mount -a
[root@server1 ~]# df -h /mssql
Filesystem                Size  Used Avail Use% Mounted on
/dev/vx/dsk/vgperp/lvol4  1.0G   19M  998M   2% /mssql
[root@server1 ~]# chown mssql:mssql /mssql

A mssql-server service is created and you can check it works with these two running processes:

[root@server1 ~]# ps -ef | grep mssql | grep -v grep
mssql    22256     1  0 12:10 ?        00:00:00 /opt/mssql/bin/sqlservr
mssql    22283 22256  8 12:10 ?        00:00:06 /opt/mssql/bin/sqlservr

If you do not want to have SQL Server database files spread everywhere like in my first trail you have to configure few environment variables:

[root@server1 mssql]# ll ~mssql
total 12
drwxr-xr-x 2 mssql mssql 4096 Nov 10 12:10 data
drwxr-xr-x 2 mssql mssql 4096 Nov 10 12:20 log
-rw-r--r-- 1 mssql mssql   51 Nov 10 12:09 mssql.conf
drwxr-xr-x 2 mssql mssql   25 Nov 10 12:10 secrets

I have decided to change few parameters (listening port) and change first the location of the master database:

[root@server1 ~]# /opt/mssql/bin/mssql-conf set network.tcpport 1443
SQL Server needs to be restarted in order to apply this setting. Please run
'systemctl restart mssql-server.service'.
[root@server1 ~]# /opt/mssql/bin/mssql-conf set filelocation.defaultdatadir /mssql/data
SQL Server needs to be restarted in order to apply this setting. Please run
'systemctl restart mssql-server.service'.
[root@server1 ~]# /opt/mssql/bin/mssql-conf set filelocation.defaultlogdir /mssql/log
SQL Server needs to be restarted in order to apply this setting. Please run
'systemctl restart mssql-server.service'.
[root@server1 ~]# /opt/mssql/bin/mssql-conf set filelocation.defaultdumpdir /mssql/dump
[root@server1 ~]# /opt/mssql/bin/mssql-conf set filelocation.defaultbackupdir /mssql/backup/
SQL Server needs to be restarted in order to apply this setting. Please run
'systemctl restart mssql-server.service'.
[root@server1 ~]# /opt/mssql/bin/mssql-conf set filelocation.masterdatafile /mssql/masterdatabasedir/master.mdf
SQL Server needs to be restarted in order to apply this setting. Please run
'systemctl restart mssql-server.service'.
[root@server1 ~]# /opt/mssql/bin/mssql-conf set filelocation.masterlogfile /mssql/masterdatabasedir/mastlog.ldf
SQL Server needs to be restarted in order to apply this setting. Please run
'systemctl restart mssql-server.service'.
[root@server1 ~]# /opt/mssql/bin/mssql-conf set memory.memorylimitmb 1024
SQL Server needs to be restarted in order to apply this setting. Please run
'systemctl restart mssql-server.service'.
[root@server1 ~]# cat ~mssql/mssql.conf
enabled = false
accepteula = Y
tcpport = 1443
defaultdatadir = /mssql/data
defaultlogdir = /mssql/log
defaultdumpdir = /mssql/dump
defaultbackupdir = /mssql/backup/
masterdatafile = /mssql/masterdatabasedir/master.mdf
masterlogfile = /mssql/masterdatabasedir/mastlog.ldf
memorylimitmb = 1024

To validate the master database file directory change you need to stop the service, move the files from OS standpoint and finally restart the service:

[root@server1 ~]# systemctl stop mssql-server
[mssql@server1 data]$ mv master.mdf /mssql/masterdatabasedir/
[mssql@server1 data]$ mv mastlog.ldf /mssql/masterdatabasedir/
[root@server1 mssql]# systemctl start mssql-server

To go fast I have used SQL Server Management Studio (SSMS) that I have installed on my Windows desktop and I have to say that it worked seamlessly:


once you supplied the credentials:


SQL Server on Linux command-line tools installation

Configure the repository:

[root@server1 ~]# cd /etc/yum.repos.d/
[root@server1 yum.repos.d]# wget https://packages.microsoft.com/config/rhel/7/prod.repo
--2021-11-10 15:23:58--  https://packages.microsoft.com/config/rhel/7/prod.repo
Resolving proxy.domain.com (proxy.domain.com)...
Connecting to proxy.domain.com (proxy.domain.com)||:8080... connected.
Proxy request sent, awaiting response... 200 OK
Length: 193 [application/octet-stream]
Saving to: ‘prod.repo’
100%[======================================================================>] 193         --.-K/s   in 0s
2021-11-10 15:23:58 (33.5 MB/s) - ‘prod.repo’ saved [193/193]

Install the tools with:

[root@server1 ~]# dnf install -y mssql-tools unixODBC-devel

You can connect to your local instance with command line (add /opt/mssql-tools/bin directory in your path):

[mssql@server1 ~]$ sqlcmd -S localhost,1443 -U SA
3> go
1> SELECT Name from sys.Databases
2> go
(5 rows affected)

Final cleaning to have all database files in good directories

get the filenames list with:

2> select name, physical_name from sys.master_files
3> go
name                                     physical_name
---------------------------------------- ----------------------------------------
master                                   /mssql/masterdatabasedir/master.mdf
mastlog                                  /mssql/masterdatabasedir/mastlog.ldf
tempdev                                  /var/opt/mssql/data/tempdb.mdf
templog                                  /var/opt/mssql/data/templog.ldf
tempdev2                                 /var/opt/mssql/data/tempdb2.ndf
tempdev3                                 /var/opt/mssql/data/tempdb3.ndf
tempdev4                                 /var/opt/mssql/data/tempdb4.ndf
tempdev5                                 /var/opt/mssql/data/tempdb5.ndf
tempdev6                                 /var/opt/mssql/data/tempdb6.ndf
tempdev7                                 /var/opt/mssql/data/tempdb7.ndf
tempdev8                                 /var/opt/mssql/data/tempdb8.ndf
modeldev                                 /var/opt/mssql/data/model.mdf
modellog                                 /var/opt/mssql/data/modellog.ldf
MSDBData                                 /var/opt/mssql/data/MSDBData.mdf
MSDBLog                                  /var/opt/mssql/data/MSDBLog.ldf

For msdb and model files you can use the below four simple command (you can create a SQL file and use -i option of sqlcmd to execute the file):

--MSDB database file and log file
alter database msdb modify file (Name = mSDBData, FILENAME = '/mssql/systemdatabasedir/MSDBData.mdf')
alter database msdb modify file (name = msdblog, filename = '/mssql/systemdatabasedir/MSDBLog.ldf');
--MODEL database file and log file
alter database model modify file (name = modeldev, filename = '/mssql/systemdatabasedir/Model.mdf')
alter database model modify file (name = modellog, filename = '/mssql/systemdatabasedir/Modellog.ldf');

For tempdb you can auto-generate the modification script with:

1> SELECT concat('alter database tempdb modify file(name=',name,',filename=''', physical_name, ''')') AS command FROM sys.master_files WHERE database_id = DB_ID('TempDB');
2> go
alter database tempdb modify file(name=tempdev,filename='/var/opt/mssql/data/tempdb.mdf')
alter database tempdb modify file(name=templog,filename='/var/opt/mssql/data/templog.ldf')
alter database tempdb modify file(name=tempdev2,filename='/var/opt/mssql/data/tempdb2.ndf')
alter database tempdb modify file(name=tempdev3,filename='/var/opt/mssql/data/tempdb3.ndf')
alter database tempdb modify file(name=tempdev4,filename='/var/opt/mssql/data/tempdb4.ndf')
alter database tempdb modify file(name=tempdev5,filename='/var/opt/mssql/data/tempdb5.ndf')
alter database tempdb modify file(name=tempdev6,filename='/var/opt/mssql/data/tempdb6.ndf')
alter database tempdb modify file(name=tempdev7,filename='/var/opt/mssql/data/tempdb7.ndf')
alter database tempdb modify file(name=tempdev8,filename='/var/opt/mssql/data/tempdb8.ndf')
(9 rows affected)

Then push the result in a SQL file modify the path to match you desired target directory (/mssql/systemdatabasedir/ for me) and execute the script. A final stop of the instance, a move of files at OS level and an instance start will finalize the modification…

AdventureWorks example database installation

To complete this initial post of SQL Server on Linux trial I have decided to import the AdventureWorks2019 Microsoft famous example database:

[mssql@server1 ~]$ cd /msql/backup
[mssql@server1 backup]$ wget https://github.com/Microsoft/sql-server-samples/releases/download/adventureworks/AdventureWorks2019.bak

Even if I love command line I have to admit that SSMS is a great piece of software and you can restore the backup file in really few mouse click. Choose the backup file:


File mapping is done automatically with value of defaultdatadir and defaultlogdir:


Not much to choose here, but useful for other personnal backups:


You can also generate a script that could be helpfull if you want to script or if, like me, trying to go further in your SQL Server understanding. Those below command could help you to generatete the right TSQL restore command:

RESTORE FILELISTONLY FROM  DISK = N'/mssql/backup/AdventureWorks2019.bak'
RESTORE HEADERONLY FROM DISK = N'/mssql/backup/AdventureWorks2019.bak'

Finally the T-SQL restore command:

1> RESTORE DATABASE [AdventureWorks2019] FROM  DISK = N'/mssql/backup/AdventureWorks2019.bak' with file = 1,
2> MOVE N'AdventureWorks2017' TO N'/mssql/data/AdventureWorks2019.mdf',
3> MOVE N'AdventureWorks2017_log' TO N'/mssql/log/AdventureWorks2019_log.ldf',
5> stats = 5
6> go
5 percent processed.
10 percent processed.
15 percent processed.
20 percent processed.
25 percent processed.
30 percent processed.
35 percent processed.
40 percent processed.
45 percent processed.
50 percent processed.
55 percent processed.
60 percent processed.
65 percent processed.
70 percent processed.
75 percent processed.
80 percent processed.
85 percent processed.
90 percent processed.
95 percent processed.
100 percent processed.
Processed 26344 pages for database 'AdventureWorks2019', file 'AdventureWorks2017' on file 1.
Processed 2 pages for database 'AdventureWorks2019', file 'AdventureWorks2017_log' on file 1.
RESTORE DATABASE successfully processed 26346 pages in 8.017 seconds (25.673 MB/sec).

A dummy select on a default example table:

1> select top(10) firstname, lastname from adventureworks2019.person.person
2> go
firstname                                          lastname
-------------------------------------------------- --------------------------------------------------
Syed                                               Abbas
Catherine                                          Abel
Kim                                                Abercrombie
Kim                                                Abercrombie
Kim                                                Abercrombie
Hazem                                              Abolrous
Sam                                                Abolrous
Humberto                                           Acevedo
Gustavo                                            Achong
Pilar                                              Ackerman
(10 rows affected)

Conclusion and next steps

Frankly this testing has really been seamless and all has really worked perfectly. Kudos to Microsoft. It worked so well that I clearly plan to test soon advanced features like:

  • Replication
  • Log Shipping
  • Always On failover cluster instance
  • Always On availability groups


About Post Author

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>