{"id":7740,"date":"2026-10-06T09:39:17","date_gmt":"2026-10-06T16:39:17","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sql\/?p=7740"},"modified":"2026-10-05T15:41:15","modified_gmt":"2026-10-05T22:41:15","slug":"pg-to-sql-connections","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sql\/pg-to-sql-connections\/","title":{"rendered":"PostgreSQL to SQL Field Notes: Connections"},"content":{"rendered":"<h2>Welcome to SQL<\/h2>\n<p>First, welcome to SQL! You\u2019re going to like this.<\/p>\n<p>Upgrading from PostgreSQL is real work, and depending on your old database, this process will vary widely in complexity. I am confident that you\u2019re going to love the mindful and modern features of SQL. Take your time, make the most of the resources built to help you in Microsoft Learn, and know there is a huge community of SQL developers ready to help along the way.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections.webp\"><img decoding=\"async\" class=\"alignnone size-full wp-image-7758\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections.webp\" alt=\"database connections image\" width=\"2048\" height=\"768\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections.webp 2048w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-300x113.webp 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-1024x384.webp 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-768x288.webp 768w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-1536x576.webp 1536w\" sizes=\"(max-width: 2048px) 100vw, 2048px\" \/><\/a><\/p>\n<h3>This blog is for the PG developer<\/h3>\n<p>Good news! The SQL standard is shared across both engines; that should help you get up to speed quickly. However, there are differences, and there aren\u2019t always equivalents. To help fast-track your learning, this series will highlight some differences worth knowing. Although some may surprise you, I believe most will be a delight.<\/p>\n<p><div class=\"alert alert-primary\">SQL, in this article and elsewhere in Microsoft documentation, means T-SQL (Transact-SQL), Microsoft\u2019s variant of the SQL standard shared across all Microsoft SQL database engines. In the Microsoft SQL world, T-SQL is referred to simply as SQL.<\/div><\/p>\n<h2>PostgreSQL connections<\/h2>\n<p><strong>Let&#8217;s start with the prerequisite of prerequisites:<\/strong> <em>connecting to the database<\/em>. A user or system attempting to interact with any database must first connect.<\/p>\n<pre><code class=\"language-csharp\">using Npgsql;\r\n\r\nusing var connection = new NpgsqlConnection(connectionString);\r\nconnection.Open();\r\n\r\n\/\/ Use the connection\r\n<\/code><\/pre>\n<p>This C# snippet makes it look easy to create a connection to a PostgreSQL database. It is! But there&#8217;s a lot you&#8217;ve had to pay attention to, too. Let&#8217;s talk through the high-level concerns you&#8217;ve had to manage.<\/p>\n<h2>Unfortunately, you already know the caveat<\/h2>\n<p>In PostgreSQL, developers always have connection management on their minds. This is because PostgreSQL uses one operating-system process per connection, making connections relatively expensive.<\/p>\n<h3>1) PostgreSQL connections are expensive<\/h3>\n<p>PostgreSQL connections are dedicated backend processes with private memory and execution state, plus OS scheduling and context-switching overhead. It&#8217;s a lot, and there&#8217;s a practical ceiling on the number of connections a server can handle before performance starts degrading.<\/p>\n<blockquote><p><strong>Processor + Memory + Overhead = Connection Cost<\/strong><\/p><\/blockquote>\n<p>This isn&#8217;t just theory. PostgreSQL&#8217;s own documentation says the default <code>max_connections<\/code> is typically only 100. Increasing it also causes PostgreSQL to allocate more resources, including shared memory. PostgreSQL is designed around the idea that connections are a resource you manage carefully.<\/p>\n<h3>2) PostgreSQL connections must be managed<\/h3>\n<p>A long-lived PostgreSQL connection isn&#8217;t necessarily a problem, but a lot of them can become a problem quickly. Idle connections still consume resources, while idle transactions trigger bigger concerns.<\/p>\n<p>You&#8217;ve probably used <code>pg_stat_activity<\/code> for this. It&#8217;s a built-in PostgreSQL system view used to monitor sessions, their state, current queries, and transaction duration to identify connections that are <code>active<\/code>, <code>idle<\/code>, or, most importantly, <code>idle in transaction<\/code>.<\/p>\n<pre><code class=\"language-sql\">SELECT *\r\nFROM pg_stat_activity;\r\n<\/code><\/pre>\n<p>You might also deploy PgBouncer, the popular PostgreSQL connection pooler, to reduce the number of physical connections reaching the server.<\/p>\n<p>You will certainly already know commands like these for ongoing management of problematic connections:<\/p>\n<ul>\n<li><code>pg_cancel_backend()<\/code><\/li>\n<li><code>pg_terminate_backend()<\/code><\/li>\n<\/ul>\n<p><div class=\"alert alert-info\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>All of this is really a matter of constant vigilance<\/strong><\/p>All of this is really a matter of constant vigilance to ensure connections are properly managed and idle transactions do not accumulate. You can fire-and-forget your databases, but as reliability and scale start to dominate the conversation, you will pay far more attention to connection and transaction management.<\/div><\/p>\n<h3>Preventing connection exhaustion<\/h3>\n<p>We also know that PostgreSQL connection limits are cluster-wide, not database-level. Each connection corresponds to a separate backend process, and <strong>the server&#8217;s finite capacity matters<\/strong>. When you move a database, the connection calculus must account for all the other databases on that server.<\/p>\n<p><div class=\"alert alert-success\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Lightbulb\"><\/i><strong>Think about that for a moment<\/strong><\/p>The typical PostgreSQL default is 100 concurrent connections, and those connections are shared across its databases. PostgreSQL lets you raise that limit, of course, but raising it increases resource requirements.<\/p>\n<hr \/>\n<p><strong>Spoiler alert: <\/strong>SQL&#8217;s connection limit is more than <em>32 thousand<\/em>!<\/div><\/p>\n<h3>PostgreSQL behavior forces developer behavior<\/h3>\n<p>Unfortunately, app developers designing apps and agents must account for the cost and limitations of PostgreSQL connections in their architecture and code. Generally, this translates to limiting concurrent connections and keeping transactions short.<\/p>\n<p><div class=\"alert alert-warning\">Long-running transactions can retain old row versions, interfere with VACUUM cleanup, increase table bloat, and contribute to transaction ID wraparound pressure.<\/div><\/p>\n<p>Consequently, PostgreSQL&#8217;s connection model dictates quite a bit of how developers must design and manage their applications, particularly in terms of connection handling and transaction management. When your app needs to break out of the box, you often must introduce additional strategies that can increase maintenance costs.<\/p>\n<h2>Great news! You\u2019re using SQL now.<\/h2>\n<p><strong>Things are different in Microsoft SQL, especially with connections.<\/strong> The biggest difference is that we manage connections and sessions in a way that generally eliminates the need to worry about exhausting server resources simply from their quantity and duration. Idle connections are comparatively inexpensive and generally aren&#8217;t an architectural concern.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-sql.webp\"><img decoding=\"async\" class=\"alignnone size-full wp-image-7759\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-sql.webp\" alt=\"database connections sql image\" width=\"1672\" height=\"941\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-sql.webp 1672w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-sql-300x169.webp 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-sql-1024x576.webp 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-sql-768x432.webp 768w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2026\/10\/database-connections-sql-1536x864.webp 1536w\" sizes=\"(max-width: 1672px) 100vw, 1672px\" \/><\/a><\/p>\n<h3>Microsoft SQL uses a worker-based architecture.<\/h3>\n<p>A connection does not require a dedicated operating-system process. Instead, Microsoft SQL assigns workers to execute work as needed. Connection pooling is also typically handled automatically by <em>ADO.NET<\/em>, making it easier to scale applications without intricate connection management strategies.<\/p>\n<pre><code class=\"language-csharp\">using Microsoft.Data.SqlClient;\r\n\r\nusing var connection = new SqlConnection(connectionString);\r\nconnection.Open();\r\n\r\n\/\/ Use the connection\r\n<\/code><\/pre>\n<p>Like the PostgreSQL sample above, this C# code makes connecting to SQL look simple. It is! But unlike the PostgreSQL example, the app generally does not need to worry about exhausting server resources simply because connections remain open or idle. Not at all. You just connect and go.<\/p>\n<h3>Flexible resource assignment<\/h3>\n<p>A SQL connection is a physical connection to the logical server. <strong>Unlike PostgreSQL, it is not mapped one-to-one with a separate operating-system process<\/strong> or dedicated worker for its lifetime. Instead, workers are assigned when requests need to execute, then returned for use by other requests. As a result, idle connections consume relatively few server resources.<\/p>\n<h4>Microsoft SQL does it for you:<\/h4>\n<ol>\n<li>Microsoft SQL supports up to 32,767 simultaneous user connections per instance.<\/li>\n<li>Microsoft SQL also supports up to 32,767 databases per instance.<\/li>\n<li>Each connection does not equate to a proportional increase in server resource consumption.<\/li>\n<li>Connection pooling further mitigates the overhead of establishing new physical connections.<\/li>\n<li>Applications can safely open and close connections at the pace that is right for the app.<\/li>\n<\/ol>\n<p><div class=\"alert alert-danger\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--ErrorBadge\"><\/i><strong>Yes, you read those first two numbers correctly<\/strong><\/p>32,767 connections and 32,767 databases. Of course, actual practical capacity depends on workload, hardware, service tier, and other resources. But the architectural difference should be clear. SQL is not designed around a small pool of dedicated backend processes.<\/div><\/p>\n<h3>Here&#8217;s how it works<\/h3>\n<p>Because Microsoft SQL manages workers and resources across connections, it reduces the need for manual resource management, monitoring, and allocation. In fact, most applications should rely on SQL and the client connection pool to do this efficiently. <strong>Manually managing connection counts without a specific reason is generally an antipattern.<\/strong><\/p>\n<p>Like PostgreSQL, SQL has connections and sessions. However, Microsoft SQL does not dedicate a separate backend process to each connection. This separation helps disassociate connection count from resource consumption.<\/p>\n<p>As a session begins executing work, Microsoft SQL dynamically assigns the workers and memory necessary to perform that work. As the work completes, those resources can be released for use by other sessions. A connection can remain open without unnecessarily tying up a dedicated process or worker.<\/p>\n<h3>You can still have control<\/h3>\n<p>All the management views you would want to see and manage connections are still there for you.<\/p>\n<pre><code class=\"language-sql\">SELECT *\r\nFROM sys.dm_exec_sessions\r\nWHERE is_user_process = 1;\r\n<\/code><\/pre>\n<p>And you can ask SQL directly how many simultaneous user connections the instance supports:<\/p>\n<pre><code class=\"language-sql\">SELECT @@MAX_CONNECTIONS AS MaxConnections;\r\n<\/code><\/pre>\n<p>On a normally configured SQL instance, the answer is:<\/p>\n<pre><code class=\"language-text\">32767\r\n<\/code><\/pre>\n<p>If you need to terminate a session, use <code>KILL<\/code> with the session ID:<\/p>\n<pre><code class=\"language-sql\">KILL &lt;session_id&gt;;\r\n<\/code><\/pre>\n<h4>This is your new default<\/h4>\n<p>Monitoring connections and killing sessions should generally be a last resort in Microsoft SQL, not a regular connection-management strategy. It&#8217;s far easier and ultimately more effective to rely on SQL and connection pooling to handle most scenarios for your application.<\/p>\n<p><strong>One less headache, one less maintenance task, one less ongoing cost to worry about.<\/strong><\/p>\n<p><div class=\"alert alert-info\">Just like any database, when you have a lot of data and a lot of query activity, it still makes sense to monitor resource usage to ensure optimal performance. SQL doesn&#8217;t make resources infinite. It simply gives you a connection architecture where idle connections don&#8217;t require dedicated server processes.<\/div><\/p>\n<h2>Congratulations<\/h2>\n<p><strong>Let me welcome you again to SQL!<\/strong> I hope it\u2019s clear that you\u2019ve joined a rich and thoughtful ecosystem.<\/p>\n<p>Scaling connections isn&#8217;t just different, it&#8217;s better. Your application can choose the connection and transaction patterns that are best for your application, rather than designing around the database&#8217;s connection architecture. That sort of freedom helps you build better. And that&#8217;s a big win for everyone!<\/p>\n<p>Happy querying!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Welcome to SQL First, welcome to SQL! You\u2019re going to like this. Upgrading from PostgreSQL is real work, and depending on your old database, this process will vary widely in complexity. I am confident that you\u2019re going to love the mindful and modern features of SQL. Take your time, make the most of the resources [&hellip;]<\/p>\n","protected":false},"author":96788,"featured_media":7761,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,672,619],"tags":[733,751,750],"class_list":["post-7740","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sql","category-sql-server-2025","category-t-sql","tag-microsoft-sql","tag-modernize","tag-postgresql"],"acf":[],"blog_post_summary":"<p>Welcome to SQL First, welcome to SQL! You\u2019re going to like this. Upgrading from PostgreSQL is real work, and depending on your old database, this process will vary widely in complexity. I am confident that you\u2019re going to love the mindful and modern features of SQL. Take your time, make the most of the resources [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7740","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/users\/96788"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/comments?post=7740"}],"version-history":[{"count":2,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7740\/revisions"}],"predecessor-version":[{"id":7765,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7740\/revisions\/7765"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media\/7761"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media?parent=7740"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/categories?post=7740"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/tags?post=7740"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}