<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hamidi Rasim</title>
    <description>The latest articles on DEV Community by Hamidi Rasim (@hamidi_rasim_695ebc2f47a5).</description>
    <link>https://dev.to/hamidi_rasim_695ebc2f47a5</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3996844%2F8c0fa6ea-e679-46d9-89a1-596f446b80dc.png</url>
      <title>DEV Community: Hamidi Rasim</title>
      <link>https://dev.to/hamidi_rasim_695ebc2f47a5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hamidi_rasim_695ebc2f47a5"/>
    <language>en</language>
    <item>
      <title>Why most MySQL to PostgreSQL converters break — and how real engines fix it</title>
      <dc:creator>Hamidi Rasim</dc:creator>
      <pubDate>Mon, 22 Jun 2026 11:36:28 +0000</pubDate>
      <link>https://dev.to/hamidi_rasim_695ebc2f47a5/why-most-mysql-to-postgresql-converters-break-and-how-real-engines-fix-it-3nn4</link>
      <guid>https://dev.to/hamidi_rasim_695ebc2f47a5/why-most-mysql-to-postgresql-converters-break-and-how-real-engines-fix-it-3nn4</guid>
      <description>&lt;p&gt;If you've ever tried converting a MySQL database to PostgreSQL (or the reverse), you've probably run into tools that do text replacement on your SQL dump.&lt;/p&gt;

&lt;p&gt;They work fine — until they don't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where regex converters fail
&lt;/h2&gt;

&lt;p&gt;The edge cases pile up fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero dates&lt;/strong&gt; (&lt;code&gt;0000-00-00&lt;/code&gt;) — PostgreSQL rejects them outright&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AUTO_INCREMENT&lt;/strong&gt; — needs to become a proper sequence with the counter set to the right value&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ENUM columns&lt;/strong&gt; — most tools skip them or flatten to VARCHAR&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backtick quoting&lt;/strong&gt; — mixed with double quotes causes silent breakage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Character sets&lt;/strong&gt; — Latin1 columns with emoji data get mangled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You only discover these after importing into production and seeing broken data.&lt;/p&gt;

&lt;h2&gt;
  
  
  A different approach
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://swapsql.com" rel="noopener noreferrer"&gt;SwapSQL&lt;/a&gt; to solve this. Instead of parsing SQL text with regex, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Loads your dump into an isolated database sandbox (real MySQL 8.0 or PostgreSQL 16)&lt;/li&gt;
&lt;li&gt;Converts engine-to-engine — schema is read from the live catalog, not from text&lt;/li&gt;
&lt;li&gt;Exports a clean &lt;code&gt;.sql&lt;/code&gt; file from the target engine&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The output is guaranteed-valid SQL because it comes from a real database, not a string manipulation script.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reverse direction: PostgreSQL to MySQL
&lt;/h2&gt;

&lt;p&gt;This is the direction almost nobody supports well. PostgreSQL has types that don't exist in MySQL:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PostgreSQL&lt;/th&gt;
&lt;th&gt;MySQL&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;uuid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CHAR(36)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gen_random_uuid()&lt;/code&gt; default maps to &lt;code&gt;(uuid())&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jsonb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;JSON&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Queryable with MySQL JSON functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;arrays&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;JSON&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stored as JSON arrays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timestamptz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DATETIME(6)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Converted to UTC, microsecond precision kept&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;identity/serial&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AUTO_INCREMENT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Counter continues from highest existing id&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;SwapSQL handles all of these, and the PostgreSQL-to-MySQL output is validated by loading it into a real MySQL server before you download it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free tier
&lt;/h2&gt;

&lt;p&gt;Dumps up to 10 MB convert for free, no account needed. SQL compresses roughly 10x, so &lt;code&gt;.sql.gz&lt;/code&gt; files are accepted — the free tier effectively covers ~100 MB of raw SQL.&lt;/p&gt;

&lt;p&gt;Try it: &lt;a href="https://swapsql.com" rel="noopener noreferrer"&gt;swapsql.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've dealt with MySQL/PostgreSQL migrations, I'd like to hear what pain points you ran into.&lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>showdev</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
