Back to Article List

PostgreSQL vs MSSQL: which one to choose

PostgreSQL vs MSSQL: which one to choose

Updated and tested 7 October 2026

Four core licences. That is the smallest SQL Server Standard purchase Microsoft will sell you, and the floor applies per virtual machine, so a 2 vCPU VPS carries the same licence bill as a 4 vCPU one. PostgreSQL on the same box costs nothing at any core count. Most comparison pages put that fact under a feature grid somewhere near the bottom.

So here is the call before the evidence. For a new project on a server you rent by the core, PostgreSQL is the default and SQL Server is the exception you make for a named reason. The named reason is usually a .NET team, an estate you already own or one specific feature you can point at. If you can't point at it, you're about to pay per core for something you would have had for free.

That isn't a swipe at SQL Server. Its optimiser will take a badly shaped correlated subquery and turn it into something sensible, the 2025 release shipped real work and nobody could call it a rebadged 2022, and there are cases further down where I'd pick it without hesitating.

What follows is licensing first, then the things that cost you time later: the locking behaviour that catches people moving in either direction, the dialect gaps that surface during a port, the tooling situation on Linux and the vector search gap, which is wide enough right now to decide some projects on its own.

MSSQL vs PostgreSQL licensing and the four-core floor

Microsoft's SQL Server licensing guidance sets a minimum of four licences per physical processor, and a minimum of four licences per virtual OSE when you licence individual virtual machines. Core licences are sold in packs of two. Standard and Enterprise are per core and commercial, with no free production tier above Express.

Read that again with a VPS in mind. A 2 vCPU virtual machine does not get you a 2-core licence. It gets you the four-core floor, so half of what you buy is paying for cores the machine doesn't have. Scaling the instance down to save money stops working below four cores, and that floor ends up shaping how you size everything else on the box.

PostgreSQL has no equivalent. It ships under the PostgreSQL Licence, a permissive BSD-style licence that grants permission to use, copy, modify and distribute without fee and without a written agreement. There is no core count and no edition matrix. Give it 96 threads and the invoice doesn't move.

Express and Developer, and what each edition permits

Express is free and licensed for production use, customer-facing databases included. The maximum size of a single relational database was 10 GB through SQL Server 2022 and is 50 GB on SQL Server 2025. Compute is limited to the lesser of one socket or four cores. The buffer pool is capped at 1,410 MB per instance. Those last two numbers did not move in 2025.

The memory cap is the one that bites on a rented server. Hand the box 32 GB of RAM and Express will still hold 1,410 MB of data pages in the buffer pool, so a 40 GB database that fits inside the size limit is reading from disk on every report. PostgreSQL on the same machine uses shared buffers plus whatever the kernel page cache gives it. The rest of the caps are in our breakdown of the SQL Server editions. What matters most there is the jump from 10 GB to 50 GB, which rescues a lot of small production databases from a Standard licence they were three months away from needing.

Developer edition is the one people misuse. Every Enterprise feature is switched on (on 2025 that's the Enterprise Developer edition, next to a new Standard Developer), it costs nothing, and the licence covers development and test only. Never production. Nothing in the installer stops you, so plenty of teams find out at audit time that the instance running their business was never licensed for it.

If your database fits inside Express and your query patterns tolerate a 1.4 GB buffer pool, SQL Server is free forever. Past that point you're weighing a per-core invoice against zero, and the comparison isn't close unless the money is buying something you can name.

No surprises on your invoice

Every plan renews at the price you see, with unmetered bandwidth and no setup fees, so next month's bill looks the same.

Read committed, snapshots and what happens when a reader meets a writer

I've spent more debugging hours on this one difference than on everything else in this article put together, so it gets more room. It also generates more confused bug reports than anything else in either direction. Relative speed has nothing to do with it.

PostgreSQL is multiversion from the ground up. The default isolation level is Read Committed, and a SELECT sees a snapshot taken at the instant the statement began. Readers don't block writers. Writers don't block readers. Two transactions updating the same row still wait on each other, and the documentation is blunt about the trade: an updating command can see an inconsistent snapshot, because it sees concurrent effects on the rows it's updating but not on other rows.

SQL Server defaults to Read Committed implemented with shared locks. A long-running report holds locks that block writers, a writer holds locks that block the report, and the folklore answer is to sprinkle WITH (NOLOCK) everywhere and accept dirty reads. That folklore is the reason so many SQL Server codebases read rows that were never committed.

First thing I run on any SQL Server instance I inherit:

SELECT name, is_read_committed_snapshot_on, snapshot_isolation_state_desc
FROM sys.databases;

If is_read_committed_snapshot_on comes back 0, Read Committed is doing it the locking way. Turning on read committed snapshot isolation gets you behaviour close to PostgreSQL's default. SQL Server parks the row versions in tempdb, where PostgreSQL keeps them in the table itself:

ALTER DATABASE MyDb SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;

The switch needs exclusive access to the database, which is what the termination clause is buying you, and it will roll back other sessions. Do it in a window.

The snapshot_isolation_state_desc column in that query reports a different setting, ALLOW_SNAPSHOT_ISOLATION, which is not the same switch.

Once RCSI is on, tempdb carries the version store. Give it a fast volume, split it into multiple data files if the instance is busy and set an alert on file growth. PostgreSQL charges for the same guarantee in a different currency: dead row versions accumulate in the heap, autovacuum cleans them up, and a table with a hot update pattern and a badly tuned autovacuum will bloat until somebody notices the disk. Check n_dead_tup in pg_stat_user_tables against your busiest tables and tune autovacuum there before the disk makes the decision for you.

Tempdb is one of those names that stops making sense once you know what's in it. Version store, hash spills, table variables, the internal worktables the optimiser creates for a big sort, and on a busy instance it's the file you'll see waits against first. The name comes from a time when it held temporary tables and not much else. Anyway.

T-SQL and PL/pgSQL: the dialect differences that cost time

Both speak SQL, and most of an ordinary CRUD application ports without anyone thinking about it. The rest is where your fortnight goes.

Identity columns and sequences

T-SQL uses the IDENTITY(1,1) column property and you read the new key back with SCOPE_IDENTITY() or an OUTPUT clause. PostgreSQL uses GENERATED ALWAYS AS IDENTITY (or the older serial types) backed by a real sequence object, and you read the key back with RETURNING:

-- SQL Server
INSERT INTO dbo.Orders (CustomerId) VALUES (42);
SELECT SCOPE_IDENTITY();

-- PostgreSQL
INSERT INTO orders (customer_id) VALUES (42) RETURNING id;

Sequences in PostgreSQL are addressable objects you can grant on, reset and share between tables. SQL Server has CREATE SEQUENCE too and hardly anybody uses it.

TOP, LIMIT and the portable form

SQL Server writes SELECT TOP (10) * FROM dbo.Orders, PostgreSQL writes SELECT * FROM orders LIMIT 10, and both support the ANSI form. If the SQL has to survive a migration, write the ANSI form:

SELECT * FROM orders
ORDER BY created_at DESC
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;

SQL Server requires an ORDER BY for OFFSET and FETCH. Paginating without one is how you get duplicate rows on page three.

String concatenation and NULL

SQL Server concatenates with + (and, from 2025, || as well), PostgreSQL with ||. The overloaded plus sign is worse than it looks: because int outranks every string type in T-SQL's data type precedence list, 'abc' + 1 tries to convert the string to an integer and fails at runtime. No concatenation happens. In PostgreSQL, 'abc' || 1 gives you abc1.

NULL behaves the same way in both once you're using the operator, in that any NULL operand poisons the result. Both also have a CONCAT() function that treats NULL as an empty string. A port that swaps + for || mechanically keeps working. A port that swaps + for CONCAT() silently changes the results of every row with a NULL in it.

Date functions

The boundary-counting behaviour gets proper treatment under the T-SQL date and time functions, which is the page I'd read before writing any conversion rules. Everything else here is tedious without being hard. GETDATE() and SYSDATETIME() become now() or current_timestamp. DATEADD(day, 7, x) becomes x + interval '7 days'. DATETRUNC(month, x) becomes date_trunc('month', x), with the datepart quoted on the PostgreSQL side.

DATEDIFF is the one that produces wrong numbers quietly; nothing errors. T-SQL's version counts datepart boundaries crossed, so DATEDIFF(year, '2005-12-31 23:59:59', '2006-01-01 00:00:00') returns 1 for a gap of one second. PostgreSQL has no direct equivalent and you subtract timestamps to get an interval, which means somebody has to decide what the original code was really asking for.

Case sensitivity and collation defaults

This is the one that breaks applications weeks after the migration, in a code path nobody tested.

A default SQL Server install on an English locale uses SQL_Latin1_General_CP1_CI_AS. CI means case-insensitive, so WHERE Email = '[email protected]' matches a stored value of [email protected]. AS means accent-sensitive, so it will not match bó[email protected].

PostgreSQL's standard collations are deterministic, which makes them case-sensitive and accent-sensitive. The same query returns zero rows. The application reads that as a bad password, so the login form stops working for everyone who capitalised their email address, and nothing in the log explains why. Three options: lower() on both sides with a matching expression index, the citext type or a nondeterministic ICU collation.

CREATE COLLATION ci_ai (provider = icu, deterministic = false, locale = 'und-u-ks-level1');

The nondeterministic route costs you performance and B-tree indexes can't use deduplication on those columns. I use citext for email and username columns and leave everything else deterministic, which has never caused me a problem and does mean the collation decision lives in the schema where somebody will see it.

Identifiers fold differently too. PostgreSQL lowercases unquoted identifiers, so a table created as "MyTable" with quotes needs quotes forever afterwards. Several of the tools that generate a PostgreSQL schema from a SQL Server one emit quoted identifiers by default, and you end up with a database where every query needs double quotes.

Schemas, dbo and public

SQL Server names objects database.schema.object, with dbo as the default schema, and a user's default schema is set server-side per database with ALTER USER Mary51 WITH DEFAULT_SCHEMA = Purchasing;. PostgreSQL uses public as the default schema and resolves unqualified names through search_path, which is a session setting.

Cross-database queries are where this turns into work. In SQL Server, SELECT * FROM Reporting.dbo.Invoices from inside another database on the same instance just works. PostgreSQL keeps separate databases in a cluster properly isolated: you need postgres_fdw or dblink to reach across, and most teams restructure those databases as schemas instead. If your application relies on cross-database joins, budget for that rewrite by name and not as a line item called migration.

PostgreSQL vs MSSQL for five common situations

Five cases where the PostgreSQL vs MSSQL answer is clear enough to state in one paragraph. The answer comes first in each.

A .NET shop

The reflex is SQL Server and the reflex is half wrong. Npgsql is a first-class EF Core provider and modern .NET on PostgreSQL is completely ordinary. If you already own SQL Server licences with cores to spare, use them. A small .NET team standing up a new service on a rented Linux box saves four core licences on day one with PostgreSQL and pays a fortnight of unfamiliarity for it.

A SaaS with a database per tenant

SQL Server wins this one outright. Thousands of databases on one instance is a pattern it handles well, cross-database queries work without extra machinery and backup and restore per tenant is a solved operation. PostgreSQL can hold many databases per cluster, and the connection accounting gets awkward quickly enough that most teams end up on pgbouncer with a schema-per-tenant design. That works, and it is a different architecture you're now maintaining.

An analytics side project

PostgreSQL, with a caveat. SQL Server's clustered columnstore indexes are excellent and one of the few places the paid engine wins on technical grounds alone. For a side project you are not buying Standard to get them.

An existing SQL Server estate

Stay. The migration cost is real, your team knows the failure modes and the licence is already paid for this year. Move specific new services to PostgreSQL if you want to and leave the estate alone. Rewriting a working system to save a licence fee is a project that overruns.

A greenfield API

PostgreSQL. Every hosting option supports it, the driver situation is good in every language, the extensions cover the things you'll want in year two and nothing about it is per-core. The exception is a small internal tool that has to feed a Microsoft reporting layer, where SQL Server Express may cover the whole job for free.

Vector search: SQL Server 2025 against pgvector

SQL Server 2025 added a native vector type, declared as VECTOR(dimensions) with an optional base type, supporting 1 to 1,998 dimensions with float32 as the default. VECTOR_DISTANCE does exact k-nearest-neighbour search. That much is generally available and it works.

What makes vector search practical at scale is not. Microsoft's documentation on vectors states that approximate vector indexes, which are DiskANN-based, and VECTOR_SEARCH are in preview. Exact kNN over a million rows means scanning a million rows. The 1,998-dimension ceiling constrains you as well, since embedding models emitting 3,072 dimensions don't fit at full width, and the half-precision float16 option that goes to 3,996 is itself a preview feature on SQL Server 2025.

pgvector has been in production use for years, is at 0.8.7 and supports PostgreSQL 13 and newer, with HNSW and IVFFlat indexes and six distance operators including cosine, L2 and inner product. Vectors store up to 16,000 dimensions, and an index takes up to 2,000 of them, 4,000 as halfvec and 64,000 as binary vectors. The pgvector repository documents the index tuning parameters that trade recall against speed, and there is a body of public experience behind those numbers that the SQL Server side does not have yet.

If retrieval-augmented search is a requirement this quarter and not a plan for next year, this section decides the whole comparison on its own. PostgreSQL wins it and it isn't close.

Your idea deserves better hosting

24/7 support 30-day money-back guaranteeRefund covers the VPS plan on your first order. Cancel anytime
Platební období

VPS.S1

28.38 RON Save  17 %
23.64 RON Měsíčně
  • 2 vCPU AMD EPYC
  • 2 GB RAMPAMĚŤ
  • 30 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně

VPS.S3

71.01 RON Save  33 %
47.33 RON Měsíčně
  • 4 vCPU AMD EPYC
  • 6 GB RAMPAMĚŤ
  • 70 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně

VPS.S4

94.70 RON Save  20 %
75.75 RON Měsíčně
  • 6 vCPU AMD EPYC
  • 8 GB RAMPAMĚŤ
  • 80 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně

EPYC VPS.P1

42.59 RON Save  22 %
33.11 RON Měsíčně
  • 2 vCPU AMD EPYC
  • 4 GB RAMPAMĚŤ
  • 40 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně
  • Auto zálohy zdarmaZahrnuje jeden slot pro zálohu, který můžete nastavit na denní, týdenní nebo měsíční spouštění.

EPYC VPS.P2

80.49 RON Save  24 %
61.54 RON Měsíčně
  • 2 vCPU AMD EPYC
  • 8 GB RAMPAMĚŤ
  • 80 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně
  • Auto zálohy zdarmaZahrnuje jeden slot pro zálohu, který můžete nastavit na denní, týdenní nebo měsíční spouštění.

EPYC VPS.P4

142.07 RON Save  23 %
108.91 RON Měsíčně
  • 4 vCPU AMD EPYC
  • 16 GB RAMPAMĚŤ
  • 160 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně
  • Auto zálohy zdarmaZahrnuje jeden slot pro zálohu, který můžete nastavit na denní, týdenní nebo měsíční spouštění.

EPYC VPS.P5

189.45 RON Save  25 %
142.08 RON Měsíčně
  • 8 vCPU AMD EPYC
  • 16 GB RAMPAMĚŤ
  • 180 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně
  • Auto zálohy zdarmaZahrnuje jeden slot pro zálohu, který můžete nastavit na denní, týdenní nebo měsíční spouštění.

EPYC VPS.P6

284.20 RON Save  25 %
213.14 RON Měsíčně
  • 8 vCPU AMD EPYC
  • 32 GB RAMPAMĚŤ
  • 200 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně
  • Auto zálohy zdarmaZahrnuje jeden slot pro zálohu, který můžete nastavit na denní, týdenní nebo měsíční spouštění.

EPYC VPS.P7

331.57 RON Save  29 %
236.82 RON Měsíčně
  • 16 vCPU AMD EPYC
  • 32 GB RAMPAMĚŤ
  • 240 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně
  • Auto zálohy zdarmaZahrnuje jeden slot pro zálohu, který můžete nastavit na denní, týdenní nebo měsíční spouštění.

Genoa VPS.G2

118.39 RON Save  20 %
94.70 RON Měsíčně
  • 2 vCPUAMD EPYC Genoa 4. generace 9xx4 s 3,25 GHz nebo podobný, na architektuře Zen 4. AMD EPYC G4
  • 4 GB DDR5PAMĚŤ
  • 50 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně
  • Auto zálohy zdarmaZahrnuje jeden slot pro zálohu, který můžete nastavit na denní, týdenní nebo měsíční spouštění.

Genoa VPS.G4

213.14 RON Save  22 %
165.76 RON Měsíčně
  • 4 vCPUProcesor AMD EPYC s dedikovanými vCPU jádry, na serverovém hardwaru pro firmy. AMD EPYC G4
  • 8 GB DDR5PAMĚŤ
  • 100 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně
  • Auto zálohy zdarmaZahrnuje jeden slot pro zálohu, který můžete nastavit na denní, týdenní nebo měsíční spouštění.

Genoa VPS.G6

426.32 RON Save  22 %
331.57 RON Měsíčně
  • 8 vCPUProcesor AMD EPYC s dedikovanými vCPU jádry, na serverovém hardwaru pro firmy. AMD EPYC G4
  • 16 GB DDR5PAMĚŤ
  • 200 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně
  • Auto zálohy zdarmaZahrnuje jeden slot pro zálohu, který můžete nastavit na denní, týdenní nebo měsíční spouštění.

Genoa VPS.G7

757.94 RON Save  22 %
592.13 RON Měsíčně
  • 8 vCPUProcesor AMD EPYC s dedikovanými vCPU jádry, na serverovém hardwaru pro firmy. AMD EPYC G4
  • 32 GB DDR5PAMĚŤ
  • 250 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku. v ceně
  • Auto zálohy zdarmaZahrnuje jeden slot pro zálohu, který můžete nastavit na denní, týdenní nebo měsíční spouštění.

AMD Ryzen VPS.R1

80.49 RON Save  18 %
66.28 RON Měsíčně
  • 1 dedikované CPU AMD Ryzen 9 7950X s 4,5 GHz nebo podobný, na architektuře Zen 4. vCPU
  • 4 GB DDR5PAMĚŤ
  • 50 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6 v ceně Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku.
  • Auto zálohy v ceně

AMD Ryzen VPS.R2

142.07 RON Save  17 %
118.39 RON Měsíčně
  • 2 dedikovaná CPU AMD Ryzen 9 7950X s 4,5 GHz nebo podobný, na architektuře Zen 4. vCPU
  • 8 GB DDR5PAMĚŤ
  • 100 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6 v ceně Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku.
  • Auto zálohy v ceně

AMD Ryzen VPS.R4

521.07 RON Save  18 %
426.32 RON Měsíčně
  • 8 dedikovaná CPU AMD Ryzen 9 7950X s 4,5 GHz nebo podobný, na architektuře Zen 4. vCPU
  • 32 GB DDR5PAMĚŤ
  • 400 GB NVMeÚLOŽIŠTĚ
  • Neměřený provoz
  • IPv4 & IPv6 v ceně Podpora IPv6 není aktuálně dostupná ve Francii, Finsku ani Nizozemsku.
  • Auto zálohy v ceně

*VAT excluded.

INCLUDED WITH EVERY PLAN

✓ No setup fees ✓1 Gbps network
✓ Full root access on KVM ✓ Free server monitoring ✓ Firewall management ✓24/7 support

SQL Server on Linux and the Windows-shaped tooling

SQL Server on Linux is real, supported and boring in the good sense. SQL Server 2025 runs on RHEL 9.x and 10.x and on Ubuntu 22.04 and 24.04, with the data files on XFS or ext4. SLES support was dropped starting with 2025. Debian has never been on the matrix. On Ubuntu 24.04 you install SQL Server 2025, because 24.04 isn't on the 2022 support matrix at all. The repository and key commands changed once apt-key was removed, so take the current ones from our walkthrough for installing SQL Server on Ubuntu.

The engine is cross-platform. The tools around it still lean Windows. SSMS 22 is Windows-only and 64-bit only, needs .NET Framework 4.8, and installs through the Visual Studio Installer now, which surprises people expecting a standalone MSI. There's no macOS or Linux build and no sign of one coming. If you need the exact steps for the current stub installer, they're in our SSMS installation guide.

The middle option went away. Azure Data Studio, the cross-platform answer for years, is retired as of 28 February 2026 with no updates and no security fixes. Microsoft's replacement is Visual Studio Code with the MSSQL extension, which is decent and improving and is not SSMS. Administering SQL Server from a Mac means that extension plus sqlcmd.

PostgreSQL's tooling is unglamorous and everywhere. psql ships with the server on every platform, pgAdmin runs anywhere, and DBeaver, DataGrip and half a dozen others treat it as a first-class target. Nobody has ever had to install a Windows VM to administer a PostgreSQL box.

Extensions and the integrated Microsoft stack

PostgreSQL's structural advantage is CREATE EXTENSION. PostGIS covers geospatial, TimescaleDB covers time series, pg_stat_statements tells you which queries are costing you and pgvector handles embeddings. New capability arrives when the extension author ships. SQL Server adds capability on its own release cadence, and some of it lands only in the edition that pays for it, so wanting the 2025 vector type on a 2019 instance means an upgrade project with application testing attached.

The counter-argument is that what a business ends up asking for is already in the SQL Server box and integrated. SSIS for ETL. SSRS for the pixel-perfect report somebody wants emailed as a PDF. SSAS and Power BI for the model on top. Always Encrypted when an auditor wants column-level encryption with keys the server never sees, Transparent Data Encryption for the at-rest tick box, Query Store for regression hunting. Some of that is edition-gated, so check the editions page before promising anything to anyone.

If your reporting layer is already Power BI, that integration argument is strong and it's why plenty of SQL Server estates will never move. If your reporting layer is a web dashboard somebody on the team wrote in React, it buys you nothing.

High availability on each

SQL Server sells a finished product here. Always On availability groups support one primary and up to eight secondary replicas, nine total, with up to five synchronous replicas since SQL Server 2019. On Windows they sit on a Windows Server Failover Cluster; on Linux the cluster layer is Pacemaker. Standard edition gets basic availability groups, limited to a single database per group, which is a much smaller feature than the name suggests. Full availability groups mean Enterprise, and Enterprise means the per-core arithmetic from the top of this article at a higher rate per core.

PostgreSQL ships the parts. Physical streaming replication and logical replication are both in core, synchronous or asynchronous, with hot standby so a replica serves read-only queries while it replays. What core does not ship is automatic failover. You add Patroni, repmgr or pg_auto_failover, plus something to move the client connections, and you own the result. Budget a fortnight for it and run a real failover drill on a quiet morning before the cluster carries anything you would miss.

Logical replication is the one part of PostgreSQL I have no settled view on. I've configured it twice, both times to move data once and throw the setup away afterwards. The honest answer on schema churn has also moved between major versions, and I'm not confident that what I saw on an older release still holds on PostgreSQL 18. If that's your use case, find someone who runs it in anger.

Migrating between SQL Server and PostgreSQL

Schema conversion is the easy part and it's what every tool demonstrates. Tables, columns, indexes and foreign keys convert mechanically with pgloader or the AWS Schema Conversion Tool. Reckon on that being the smaller share of the work.

The rest is stored procedures, the application's inline SQL and the behaviours nobody wrote down. T-SQL procedures become PL/pgSQL functions with different error handling, different transaction semantics inside a procedure and no direct equivalent for some of the table-valued patterns. Triggers rewrite. Anything using OUTPUT, MERGE or CROSS APPLY needs a human. Anything relying on case-insensitive comparison needs the collation decision from earlier, applied consistently, before the first row moves.

AWS's Babelfish takes a different route by speaking the TDS wire protocol, so an existing application can keep sending T-SQL to PostgreSQL. It's a real option for buying time on a legacy application. It is also not full T-SQL coverage, so test the awkward procedures in week one and not in week nine. Going the other direction, Microsoft's SQL Server Migration Assistant is no help: its sources are Access, Db2, MySQL, Oracle and SAP ASE, with no PostgreSQL edition.

Whatever the tool, the pattern that works is dual-running. Point a read replica of the application at the new database. Run the same queries against both. Diff the results. Only then move writes. Our notes on SQL Server connection strings are worth reading alongside the Npgsql equivalents while you set that up, because encryption defaults differ on both sides and that's where the first hour of failures comes from.

One decision worth making early is where the thing runs. Both engines are happy on a Linux VPS with NVMe storage, and if you want SQL Server without building the box by hand, the LumaDock one-click MSSQL template deploys the engine on Ubuntu in minutes. No SQL Server licence comes with it, so you either buy the cores or keep the instance inside Express or Developer terms, and the four-core minimum from the top of this article is still yours to work out. PostgreSQL, being PostgreSQL, is a single apt command on any image you like.

Two more pages if you want the neighbouring arguments. Our SQL Server and MySQL comparison covers a different set of trade-offs, and the Strapi 5 on PostgreSQL guide shows what a production PostgreSQL setup looks like end to end if you'd rather see it than read about it.

Every SQL Server vs Postgres thread I've read ends the same way, with somebody posting a benchmark from their laptop and somebody else posting a different one. Load your real schema instead, run your ten slowest reports and watch what each planner does with them. Benchmarks from strangers, mine included, tell you nothing about your data.

Questions?

Can I use SQL Server Management Studio with PostgreSQL?

No, SSMS manages platforms built on the Microsoft SQL Database Engine, meaning SQL Server, Azure SQL Database, Azure SQL Managed Instance and SQL database in Fabric, and PostgreSQL is not among them. Microsoft's own PostgreSQL tool is the PostgreSQL extension for Visual Studio Code, which connects to local, on-premises and cloud PostgreSQL servers on Windows, macOS and Linux. It can also open a psql terminal session straight from its connection list.

About the author

Oliver P. Redmond

I studied history and, for a while, expected to end up in archives (or academic publishing). Instead I took a copy-editing job with a small specialist publisher, learnt rather more about XML than the job description had implied and gradually found myself editing software manuals. Naturally, technical writing followed from there.

What I like about infrastructure is the accumulated quality. A modern service may have an elegant interface sitting on top of conventions and protocols that are sometimes older than the person using it. And so, understanding a system often means following those layers backwards. I write mostly about Linux systems, virtual machines and storage. I live in Bristol and still use a fountain pen for notes.

Deploy your next project in seconds

Bring your winning ideas online faster, with modern hardware and unmetered bandwidth. Join a European cloud trusted by thousands of developers and businesses worldwide.