SQL Server to PostgreSQL migration tools compared: schema conversion, data type mapping, and eight documented mappings that change your data
Twelve tools that move a SQL Server database to PostgreSQL, and the part no feature list covers. We took every type mapping in the AWS SQL Server to Aurora PostgreSQL playbook and checked it against the documentation of the product it maps to. Eight do not survive the check, including a money column that quietly loses two decimal places and a GUID column too short to hold a GUID. All three tables are below, with the query that catches each one before the load.
No credit card required.
Field mapping auto-plugged · tap a port to rewire
Plug a source port into
Transform on this cable
JSON in
JSON out
5 sample records ready
Vendor documentation read 1 September 2026 · Last updated September 2026
Which SQL Server to PostgreSQL migration tool should you use?
Use AWS DMS with DMS Schema Conversion for most moves onto RDS or Aurora PostgreSQL, because it covers schema conversion, bulk load and change capture in one place and produces an assessment report you can scope from. Choose Babelfish for Aurora PostgreSQL instead when the blocker is thousands of lines of T-SQL rather than the data, since it understands T-SQL and answers on the same wire protocol and port your existing clients already use. Use pgloader or sqlserver2pgsql when you want a free, scriptable conversion you can read and commit to a repository. Whichever you pick, do not accept its default type mapping: the eight rows in the next table are all published vendor guidance, and each one produces valid DDL, loads without an error, and changes what your data means.
The correction worth making early: almost every page in this category ranks tools by how much of the schema they convert. That is the wrong question, because nearly everything in a SQL Server schema is an ordinary table that every tool converts. The question that decides whether your migration succeeds is what each tool does with the dozen types where SQL Server and PostgreSQL genuinely disagree, and whether it tells you. For the wider category see data migration tools, and for the ongoing case rather than the one time move, Postgres ETL tools.
Eight mappings AWS publishes that its own sources contradict
The AWS SQL Server to Aurora PostgreSQL migration playbook is the most detailed public guide for this route, and it is genuinely useful. It is also, in places, wrong in ways that are checkable in about five minutes. We took every type mapping it publishes and compared it to the primary documentation of the product being mapped to, on 1 September 2026. Eight did not survive. Three of them are contradicted by another page of the same playbook.
| Type or feature | What the playbook says | What contradicts it | What we would ship |
|---|---|---|---|
| MONEY | Maps to PostgreSQL MONEY, rated "PostgreSQL identical compatibility: Yes" | The PostgreSQL manual states the money type's "fractional precision is determined by the database's lc_monetary setting", and its documented range assumes two fractional digits. Microsoft states SQL Server money is "accurate to a ten-thousandth of the monetary units", which is four. | numeric(19,4). Never the PostgreSQL money type |
| TEXT, NTEXT and IMAGE | Prose on the data types page: "AWS SCT converts TEXT and NTEXT data types to LONGTEXT and IMAGE to LONGBLOB" | PostgreSQL has no LONGTEXT type and no LONGBLOB type. Both are MySQL types, and neither appears in the PostgreSQL built-in type list. The table further down the same AWS page gives NTEXT to TEXT and IMAGE to BYTEA, contradicting its own paragraph. | text for TEXT and NTEXT, bytea for IMAGE |
| ROWVERSION | Maps to TIMESTAMP(p) in the data type table | Microsoft states rowversion "is just an incrementing number and does not preserve a date or a time", and that a nonnullable rowversion column "is semantically equivalent to a binary(8) column". The AWS worked example lower on the same page emits VARCHAR(8000) instead, contradicting the table above it. | bytea, or drop the column and use an explicit version integer |
| UNIQUEIDENTIFIER | Maps to CHAR(16) in the data type table | The AWS SCT worked example on the same page emits UUID. CHAR(16) is neither form of a GUID: the canonical text form is 36 characters and the binary form is 16 bytes, so a text GUID written into CHAR(16) is truncated at the first 16 characters. | uuid |
| NCHAR and NVARCHAR | Map to CHAR(n) and VARCHAR(n), rated "PostgreSQL identical compatibility: Yes" | The collations page of the same playbook lists NCHAR and NVARCHAR as "Not Supported" on Aurora PostgreSQL, lists UTF16 as "Not Supported", and rates collation handling at zero automation against four stars for data types. | text or varchar(n) on a UTF-8 database, with the encoding change planned deliberately |
| BIT | Maps to PostgreSQL BIT, rated "PostgreSQL identical compatibility: Yes" | PostgreSQL bit is a fixed-length bit string type, listed in the manual separately from boolean. SQL Server BIT holds 0, 1 or NULL and is compared with integers, so every application predicate of the form WHERE IsActive = 1 stops working against a bit string column. | boolean |
| GEOMETRY and GEOGRAPHY | Map to GEOMETRY and GEOGRAPHY, rated "PostgreSQL identical compatibility: Yes" | Neither type appears in the PostgreSQL built-in data type list. Both come from PostGIS, a separate extension that has to be installed and enabled, so the mapping is only correct on a database somebody has already prepared. | PostGIS geometry and geography, installed as an explicit prerequisite |
| The worked example itself | A DDL block on the data types page labeled "Source SQL Server compatible DDL" | Its columns are BINARY_FLOAT, BINARY_DOUBLE, CLOB, NUMBER, VARCHAR2, XMLTYPE, LONG and RAW, which are Oracle type names, not SQL Server ones. Its output converts INTEGER and SMALLINT to numeric(38,0), which is Oracle NUMBER(38) behavior. A SQL Server INT is a 32-bit integer and belongs in a PostgreSQL integer. | Read the playbook prose as guidance and re-derive every example against your own schema |
None of this makes the playbook useless, and we still recommend reading it. It makes the point that a published mapping is a starting position rather than a fact. The money row is the one to sit with, because both vendors document the problem independently and neither documents the combination: Microsoft says SQL Server money is accurate to a ten-thousandth, PostgreSQL says its own money type takes its fractional precision from a locale setting, and AWS says the two are identically compatible. Two of those three statements are true.
SQL Server to PostgreSQL migration tools compared
Pricing models rather than price tags, because every vendor here except us either quotes or meters, and any figure printed on this page would be stale within a quarter. Where a tool is wrong for a job, the last column says so.
| Tool | Approach | Best for | Pricing model |
|---|---|---|---|
| AWS DMS | Managed replication instance: full load, then change capture from the SQL Server transaction log | Cutting over to RDS or Aurora PostgreSQL with seconds of downtime rather than a weekend | Per hour of replication instance, plus storage and data transfer |
| DMS Schema Conversion | Converts the schema in the console and produces an assessment report listing every object it could not convert | Sizing the conversion work before you commit to a cutover date | No license charge, you pay for the infrastructure it runs against |
| AWS SCT | Downloadable schema conversion tool, the desktop predecessor to the console experience | Converting offline, and producing the assessment report that scopes stored procedure work | Free download |
| Babelfish | Aurora PostgreSQL capability that understands T-SQL and speaks the TDS wire protocol, by default on port 1433 | When the blocker is thousands of lines of T-SQL in an application you cannot rewrite | A capability of Aurora PostgreSQL rather than a separately licensed product |
| pgloader | One command that reads a source schema, converts it with a documented casting ruleset and loads the data | A free, scriptable, reviewable conversion you can commit to a repository | Free |
| sqlserver2pgsql | Converts a SQL Server DDL dump into PostgreSQL DDL and can generate a Pentaho job to move the data | Teams who want the schema conversion as a readable text transformation rather than a black box | Free |
| Azure DMS | Managed migration into Azure Database for PostgreSQL, paired with Data Factory for orchestration | Estates already standardized on Azure | Service tiers plus the compute the migration runs on |
| Google Cloud DMS | Managed migration into Cloud SQL and AlloyDB with a conversion workspace for heterogeneous pairs | SQL Server into Cloud SQL for PostgreSQL or AlloyDB | Heterogeneous migrations are charged, homogeneous ones are not |
| Striim | Streaming change capture with in-flight processing between SQL Server and PostgreSQL | Continuous replication where the SQL Server instance is staying online long term | Subscription, quoted by capacity |
| Debezium | Kafka Connect source connector that turns SQL Server CDC tables into a change stream | Teams already running Kafka who want the stream rather than a finished migration | Free, you pay for the Kafka platform underneath it |
| EDB | Commercial PostgreSQL distribution with migration tooling and compatibility features | Regulated estates that want a vendor with a support contract standing behind PostgreSQL | Subscription, quoted |
| Adapters | Field level mapping between SQL Server, PostgreSQL and the rest of your stack, run once for a backfill then incrementally | The common outcome where SQL Server does not switch off and the two databases have to agree indefinitely | Flat $49 a month, not metered by rows |
What each one will bite you with
- AWS DMS
- Change capture needs SQL Server Agent running. The log truncation point does not advance until capture has gathered changes, so a paused task grows the log
- DMS Schema Conversion
- Read the generated DDL rather than accepting it. Several of its documented default mappings are wrong for money, GUIDs and rowversion
- AWS SCT
- Its own playbook table and its own worked example disagree on what UNIQUEIDENTIFIER and ROWVERSION become. Trust the output you test, not the table
- Babelfish
- It runs T-SQL "with some differences", does not support MARS, and supports TDS 7.1 through 7.4. Compatibility has to be measured against your code, not assumed
- pgloader
- Its reference states views are not migrated and triggers are not migrated. Its MS SQL support is less exercised than its MySQL support
- sqlserver2pgsql
- Community maintained, so check recent activity and coverage of your SQL Server version before you depend on it
- Azure DMS
- Source and target coverage varies by pair and changes. Confirm the current support matrix rather than assuming parity with AWS
- Google Cloud DMS
- Confirm the current heterogeneous pair list before planning around it, because the supported set has grown in stages
- Striim
- Priced as a streaming platform, which is heavy if all you need is one cutover
- Debezium
- It depends on SQL Server CDC being enabled, and landing the events in PostgreSQL is a second component you build and own
- EDB
- Its strongest compatibility story is Oracle rather than SQL Server. Scope that against your actual dialect
- Adapters
- We are not a bulk schema converter. For a 4,000 table lift and shift, use DMS Schema Conversion
Five of the twelve cost nothing to license, which is unusual for a software category and worth saying plainly. If budget is the reason you are reading a comparison table, the answer is that AWS SCT, DMS Schema Conversion, pgloader, sqlserver2pgsql and Debezium are all free, and the money in a SQL Server to PostgreSQL migration goes to engineer time rather than to tooling. Our own price is flat and published, which is why ours is the only figure on this page.
SQL Server to PostgreSQL data type conversion, and the mapping that looks right
Most type mapping tables published for this pair list a SQL Server type and a PostgreSQL type and stop. That is the easy half. The column that matters is the third one, because these are the mappings a converter picks by default, and every one of them produces a schema that deploys without a single error.
| SQL Server type | Target we would defend | The mapping that looks right | What it costs you |
|---|---|---|---|
| BIT | boolean | bit | PostgreSQL bit is a bit string, not a truth value. Every WHERE flag = 1 in the application stops matching |
| TINYINT | smallint | smallint | Correct, but the source is unsigned 0 to 255 and the target is signed. Add a CHECK constraint or you lose the guarantee |
| MONEY | numeric(19,4) | money | PostgreSQL money precision comes from lc_monetary, typically two places. The third and fourth decimals disappear silently |
| SMALLMONEY | numeric(10,4) | money | Same locale dependency, and the dump will not reload cleanly into a database with a different lc_monetary |
| DATETIME | timestamp(3) | timestamp | Not lossy, but misleading. The source can only ever hold .000, .003 and .007 in the milliseconds, so a full precision target implies accuracy that was never there |
| SMALLDATETIME | timestamp(0) | timestamp | The source has one minute resolution with seconds always zero. A full precision column hides that from everyone reading the schema later |
| DATETIME2(p) | timestamp(p) | timestamp(6) | DATETIME2 reaches seven fractional digits and PostgreSQL stops at six, so a datetime2(7) column loses its last digit |
| DATETIMEOFFSET | timestamptz | timestamp | The only SQL Server type that carries an offset. Dropping to a naive timestamp destroys the one piece of information it existed to keep |
| UNIQUEIDENTIFIER | uuid | char(16) | A GUID is 36 characters as text and 16 bytes as binary. char(16) truncates the text form mid value |
| ROWVERSION | bytea | timestamp(p) | Microsoft says it does not preserve a date or a time. Presenting a counter as a timestamp invites someone to report on it |
| NVARCHAR(n) | varchar(n) on UTF-8 | varchar(n) | Right answer, wrong assumption. PostgreSQL counts characters not bytes and does not do UTF-16, so the encoding move is real work, not a rename |
| VARCHAR(MAX) | text | text | Correct. Worth confirming the source collation first, because a non-Unicode column may not be valid UTF-8 |
| SQL_VARIANT | No equivalent | varchar(8000) | Stringifying it loses the type tag that made it a variant. Model the real types into real columns instead |
| HIERARCHYID | ltree, or a path column | varchar(n) | The methods that made it useful, GetAncestor and IsDescendantOf, do not come with the string |
The datetime rows deserve a note, because they are the ones people argue about. Mapping DATETIME to a full precision timestamp is not lossy and nothing breaks. It is still worth using timestamp(3), because a SQL Server datetime can only ever hold .000, .003 or .007 in its milliseconds field, and a microsecond precision column tells every future reader that the data is more accurate than it is. The same construct by construct treatment for the other two commercial routes into Postgres is in Oracle to PostgreSQL migration tools and MySQL to PostgreSQL migration tools.
Eight failures that report success
A SQL Server to PostgreSQL migration rarely fails loudly. It converts cleanly, loads cleanly, reconciles on row counts, and is wrong. Every row here is documented behavior from a primary manual rather than folklore, and the last column is the check that catches it while it is still cheap.
| Failure | What you see | Why it happens | How to catch it first |
|---|---|---|---|
| Money loses two decimal places | Row counts reconcile exactly and financial totals move by a rounding amount | A SQL Server money column, accurate to a ten-thousandth, landed in the PostgreSQL money type, whose fractional precision is set by lc_monetary and is usually two places | SELECT count(*) WHERE amount <> round(amount, 2) on the source. Any non-zero result means you are carrying data the target will drop |
| GUIDs arrive truncated | Foreign key lookups start missing, and the values look almost right | UNIQUEIDENTIFIER converted to char(16) rather than uuid, so a 36 character text GUID kept only its first 16 characters | SELECT length(id::text) FROM the target after a trial load. Anything other than 36 means the column is too narrow |
| Boolean predicates stop matching | Screens render as if every record is inactive, with no error in the logs | BIT converted to the PostgreSQL bit string type. WHERE IsActive = 1 no longer compares the way the application expects | Grep the application for = 1 and = 0 against known bit columns before cutover, then convert those columns to boolean |
| Timestamps in a loop become identical | Rows inserted by one stored procedure all share the same created_at to the microsecond | GETDATE() was translated to now(). The PostgreSQL manual states now() is transaction_timestamp() and that its value does not change during the transaction | Use clock_timestamp() where the source relied on time advancing inside a transaction, and now() where it did not |
| Duplicates start appearing | A unique index that held for years begins accepting two spellings of the same value | The SQL Server collation was case insensitive, so the index rejected values differing only by case. The PostgreSQL default collation is case sensitive | SELECT lower(col), count(*) FROM t GROUP BY 1 HAVING count(*) > 1 on the source. Every group is a duplicate waiting to be created |
| Sort order changes | Reports and paginated lists come back reshuffled with no code change | Different collation rules, so uppercase and lowercase interleave differently between the two engines | Run the same ORDER BY on both databases and diff the first two hundred rows |
| The transaction log fills the disk | The source SQL Server runs out of space during a migration that appeared to be paused and harmless | With CDC enabled the log truncation point does not advance until the capture process has gathered the changes. A stopped capture means a log that only grows | Alert on log space on the source for the entire migration window, not just during the load |
| Identity columns collide after go-live | Everything works until the first insert after cutover, which fails on the primary key | The identity column was created without setting its sequence to the current maximum carried over from SQL Server | Run setval on every sequence as the final step of cutover, then insert and roll back one row per table as a smoke test |
The timestamp row is the subtlest and the most interesting, because both halves are correct in isolation. GETDATE() maps to now() in every conversion guide including the AWS playbook summary table, and that is the right function in almost every context. It is wrong in exactly one: inside a transaction. The PostgreSQL manual states that now() is transaction_timestamp() and that its value does not change during the transaction, calling that a feature. SQL Server GETDATE() has no such behavior, so a stored procedure that stamped a hundred rows with a hundred different times now stamps them all with one.
The limits that decide the plan
.000, .003, .007
The only millisecond values a SQL Server datetime column can hold. Microsoft documents it as "Rounded to increments of .000, .003, or .007 seconds", and advises avoiding datetime for new work.
Microsoft Learn, datetime (Transact-SQL), read 1 September 2026
ten-thousandth
The documented accuracy of SQL Server money. The same page warns you can experience rounding errors through truncation and to use decimal instead if the values are used in calculations.
Microsoft Learn, money and smallmoney, read 1 September 2026
lc_monetary
What determines the fractional precision of the PostgreSQL money type. The manual also warns that money data may not load into a database with a different lc_monetary setting.
PostgreSQL 18 manual, monetary types, read 1 September 2026
0 of 4
The automation rating AWS gives collation handling in its own SQL Server to Aurora PostgreSQL playbook, on the same four star scale where it rates data type conversion four out of four.
AWS migration playbook, collations, read 1 September 2026
Not Supported
What that same playbook says about NCHAR, NVARCHAR and UTF16 on Aurora PostgreSQL, in a playbook whose data type table calls NVARCHAR identically compatible.
AWS migration playbook, collations summary, read 1 September 2026
1433
The TDS port Babelfish for Aurora PostgreSQL listens on by default, so an existing SQL Server client can connect without changing its driver. PostgreSQL clients still use 5432.
Amazon Aurora user guide, read 1 September 2026
The collation rating is the one that should change your project plan. AWS rates data type conversion at four stars for automation and collation handling at zero on the same scale, in the same playbook. If your SQL Server databases use a case insensitive collation, which is the common default, then the part of this migration the tooling does not help with at all is the part that decides whether your unique constraints still mean what they meant.
How to migrate SQL Server to PostgreSQL in six steps
-
01
Inventory the types before you pick a tool
Query sys.columns joined to sys.types on the source and group by type name. You are looking for six things: money and smallmoney, uniqueidentifier, rowversion, bit, nvarchar, and every datetime variant. That single query tells you more about how hard this migration will be than any vendor assessment report, and it takes a minute to write.
-
02
Read the generated DDL, do not accept it
Run DMS Schema Conversion or AWS SCT, then open the output and compare it to the type table on this page. The mappings for money, uniqueidentifier, rowversion and bit are the four to check first, because each one produces valid DDL, loads without error, and changes what the column means. Commit the corrected DDL to your repository so the conversion is reviewable.
-
03
Prove the data on the source
For every money column, count rows where the value differs from itself rounded to two places. For every unique index on a text column, group by lower() and look for collisions. For every datetime column, check the earliest value against the 1753 floor. Each is a one line query, and each one prevents a class of failure that otherwise surfaces after go-live.
-
04
Decide between rewriting T-SQL and running Babelfish
This is the fork that sets the timeline. If the business logic lives in stored procedures and nobody has budget to rewrite them, Babelfish keeps the T-SQL and the wire protocol, and the work becomes compatibility testing instead of translation. If the logic lives in the application, rewrite and target plain PostgreSQL. Decide this before conversion, not after.
-
05
Load, then reconcile on values rather than counts
Do a full load into an empty PostgreSQL database. Then compare, per table, the row count, the SUM of every numeric column, the MIN and MAX of every date column, and a hash of the primary keys. Row counts alone reconcile perfectly on a migration that has quietly dropped two decimal places from every money column.
-
06
Turn on change capture and watch the source log
SQL Server CDC needs SQL Server Agent running. Start the change stream from the snapshot position and watch replication lag fall towards zero. Watch the source transaction log at the same time, because the truncation point does not advance until capture has gathered the changes, and a stalled task turns into a full disk on the database you are still depending on.
Who moves from SQL Server to PostgreSQL, and why
Escaping a per core licence
The commercial reason most of these projects get funded. The database work is the visible part and the stored procedure rewrite is the part that decides the date.
Moving to a managed PostgreSQL
RDS, Aurora, Cloud SQL and AlloyDB all take PostgreSQL. The migration is the price of admission to the operational model you actually wanted.
Leaving Windows behind
Estates consolidating on Linux often find SQL Server is the last Windows dependency. That makes the migration an infrastructure decision rather than a database one.
Keeping the application, changing the database
Where Babelfish earns its place. The T-SQL and the driver stay, the licence goes, and the work becomes compatibility testing.
Keeping both databases live
The common outcome nobody plans for. A reporting tool, a department or an old integration keeps SQL Server alive, and the one time move becomes an ongoing sync.
Feeding a warehouse on the way past
Several teams take the opportunity to land the same data in Snowflake or BigQuery while the mapping work is already open in front of them.
Where we are the wrong tool
A comparison page written by a vendor is worth reading only if the vendor says where they lose. Five cases where you should use something else.
- A pure lift and shift of a 4,000 table schema. Run DMS Schema Conversion. That is what it is built for and we are not going to pretend otherwise.
- Converting stored procedures and T-SQL business logic. Nobody converts these well, ourselves included, and any vendor claiming otherwise is selling you a review job you have not budgeted.
- Keeping a T-SQL application running unchanged. That is exactly what Babelfish does and we do not do it. If your blocker is the dialect rather than the data, start there.
- Air gapped environments with no outbound network. We are a hosted service. If nothing may leave your network, this is the wrong shape of product.
- One off migrations that genuinely finish. If SQL Server really does switch off next month, you do not need an ongoing sync and you should not pay for one.
Four questions to ask any migration vendor
Show me your default type mapping, in writing
Any tool worth using publishes its casting rules. Then check them, because published does not mean correct: the mappings on this page are all taken from a major vendor's own documentation and several of them are contradicted by the documentation of the product they are mapping to. Ask specifically what happens to money, uniqueidentifier, rowversion and bit.
What happens to stored procedures, functions and triggers?
The honest answer from most tools is that they produce a report and you do the work. Ask for the assessment report against your actual schema before you sign anything, not against a demo schema, and ask how many objects came back needing manual conversion.
How do you reconcile, and on what?
If the answer is row counts, keep looking. Row counts reconcile perfectly on a migration that has rounded every money column and truncated every GUID. Ask for value level checks: sums, hashes and distinct counts per column.
What does this cost if the project runs three months long?
Per hour and per row pricing both grow with delay, and migrations are the projects most likely to slip. Ask the vendor to price the overrun case rather than the happy path, because the overrun case is the one you are more likely to live in.
Related migration and integration guides
SQL Server is one route into PostgreSQL among several. These cover the neighboring engines, the ongoing sync case, and the cost model behind a migration program.
Data migration tools
The pillar above this page: twelve tools, type mapping traps and cutover methods.
Convert SQL Server T-SQL to PostgreSQL
Statement by statement, with the functions that convert cleanly and answer differently.
SQL Server to PostgreSQL migration guide
The walkthrough version: CDC setup, cutover sequencing and rollback.
Oracle to PostgreSQL migration tools
The other commercial escape route, where PL/SQL rather than types dominates.
MySQL to PostgreSQL migration tools
Same shape of problem, different traps: unsigned integers and TINYINT(1).
Change data capture tools
The mechanism behind a cutover measured in seconds instead of a weekend.
Questions buyers ask about SQL Server to PostgreSQL migration
- How do I migrate a SQL Server database to PostgreSQL?
- Convert the schema, move the rows, then rewrite the T-SQL, and treat those as three separate projects. AWS Schema Conversion Tool or DMS Schema Conversion handles the first, AWS Database Migration Service the second, and the third is hand work. The step teams skip is auditing the generated type mapping before the first load, because that is where a clean conversion quietly changes what your columns mean.
- What is the best SQL Server to PostgreSQL migration tool?
- AWS DMS with Schema Conversion for most moves onto RDS or Aurora, because it covers schema, bulk load and change capture in one place. Babelfish for Aurora PostgreSQL when the blocker is the application rather than the data, since it speaks T-SQL over the same wire protocol. pgloader when you want a scriptable, free conversion you can read. The choice matters less than whether you override the default type mapping first.
- Can SQL Server be converted to PostgreSQL automatically?
- Tables and data convert automatically. Stored procedures, functions, triggers and anything using T-SQL specific syntax do not, and neither do collations. AWS rates data type conversion at four stars for automation in its own playbook and rates collation handling at zero stars on the same scale. Budget hand conversion for every stored routine and every query the application sends.
- How long does a SQL Server to PostgreSQL migration take?
- Estimate from the T-SQL, not the data. Copying rows is bounded work that DMS finishes in hours for most databases. Rewriting stored procedures, replacing TOP with LIMIT, replacing ISNULL with COALESCE and untangling case insensitive comparisons is unbounded. A thin ORM over a simple schema moves in weeks. A database with thousands of lines of business logic in stored procedures is a two quarter program.
- How much does a SQL Server to PostgreSQL migration cost?
- The tooling is mostly free and the labor never is. AWS SCT is a free download, DMS Schema Conversion carries no license charge, and pgloader costs nothing. AWS Database Migration Service bills by the hour of replication instance. What you actually pay for is engineer time spent converting stored procedures and validating results, which is why the licence you are escaping is usually the smaller number.
- Is PostgreSQL compatible with SQL Server?
- At the SQL standard level, largely. At the dialect level, no. PostgreSQL has no NVARCHAR, no UTF-16, no column level case insensitive collation in the SQL Server sense, no TOP, no ISNULL, and no money type that behaves like SQL Server money. Ordinary SELECT and INSERT statements move without friction. Anything written specifically for T-SQL needs rewriting or a compatibility layer such as Babelfish.
- What data types do not convert from SQL Server to PostgreSQL?
- SQL_VARIANT has no equivalent and AWS says so plainly. HIERARCHYID has none either and lands as text. NVARCHAR has no direct target because PostgreSQL does not implement UTF-16. ROWVERSION is a binary counter rather than a time, so it should not become a timestamp. MONEY converts to a PostgreSQL type of the same name that behaves differently, which is worse than not converting.
- Can you migrate SQL Server to PostgreSQL with zero downtime?
- With change data capture, yes, down to a cutover of seconds. Load a consistent snapshot, then stream changes from the SQL Server transaction log until the target has caught up, then switch. SQL Server CDC requires SQL Server Agent to be running, and the log truncation point does not advance until the capture process has gathered the changes, so a paused migration grows the transaction log.
- What is the SQL Server Migration Assistant for PostgreSQL?
- It does not exist, and the confusion costs teams a week. Microsoft SQL Server Migration Assistant moves other databases into SQL Server, not out of it, so there is no SSMA edition that targets PostgreSQL. The tool people are looking for is AWS Schema Conversion Tool or DMS Schema Conversion, both of which convert SQL Server schemas to PostgreSQL and produce an assessment report.
- What goes wrong in a SQL Server to PostgreSQL migration?
- The conversions that succeed and change your data. A money column lands in a PostgreSQL type whose decimal precision is a locale setting. A uniqueidentifier lands in a column too short to hold a GUID. A rowversion counter becomes a timestamp. A case insensitive unique index becomes case sensitive, so duplicates start arriving. None of those raise an error during the migration.
For the people cost that dominates every migration program, read what a data migration really costs. For the difference between moving data once and moving it continuously, see ETL vs ELT, and for the wider vendor landscape, the best data integration tools. If the destination under discussion is a warehouse rather than another transactional database, the constraint model changes entirely and the tool set with it, which is covered on SQL Server to Snowflake migration tools.
Migrate off SQL Server once, then keep PostgreSQL in agreement with everything else
Map the fields once, run the backfill, then let the same mapping run incrementally with retries, alerts and per-record logs. From $49 a month, not metered by rows.
No credit card required.