diff --git a/src/main/kotlin/com/coder/gateway/CoderSettingsConfigurable.kt b/src/main/kotlin/com/coder/gateway/CoderSettingsConfigurable.kt
index 1e5f2354..e6e7a13a 100644
--- a/src/main/kotlin/com/coder/gateway/CoderSettingsConfigurable.kt
+++ b/src/main/kotlin/com/coder/gateway/CoderSettingsConfigurable.kt
@@ -2,6 +2,7 @@ package com.coder.gateway
 
 import com.coder.gateway.services.CoderSettingsService
 import com.coder.gateway.services.CoderSettingsStateService
+import com.coder.gateway.settings.CODER_SSH_CONFIG_OPTIONS
 import com.coder.gateway.util.canCreateDirectory
 import com.intellij.openapi.components.service
 import com.intellij.openapi.options.BoundConfigurable
@@ -109,6 +110,13 @@ class CoderSettingsConfigurable : BoundConfigurable("Coder") {
                         CoderGatewayBundle.message("gateway.connector.settings.disable-autostart.comment")
                     )
             }.layout(RowLayout.PARENT_GRID)
+            row(CoderGatewayBundle.message("gateway.connector.settings.ssh-config-options.title")) {
+                textArea().resizableColumn().align(AlignX.FILL)
+                    .bindText(state::sshConfigOptions)
+                    .comment(
+                        CoderGatewayBundle.message("gateway.connector.settings.ssh-config-options.comment", CODER_SSH_CONFIG_OPTIONS)
+                    )
+            }.layout(RowLayout.PARENT_GRID)
         }
     }
 
diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
index 1a491e64..a6190d94 100644
--- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
+++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
@@ -255,6 +255,9 @@ class CoderCLIManager(
             if (settings.headerCommand.isNotBlank()) escapeSubcommand(settings.headerCommand) else null,
            "ssh", "--stdio",
             if (settings.disableAutostart && feats.disableAutostart) "--disable-autostart" else null)
+        val extraConfig = if (settings.sshConfigOptions.isNotBlank()) {
+            "\n" + settings.sshConfigOptions.prependIndent("  ")
+        } else ""
         val blockContent = workspaceNames.joinToString(
             System.lineSeparator(),
             startBlock + System.lineSeparator(),
@@ -268,7 +271,9 @@ class CoderCLIManager(
                   UserKnownHostsFile /dev/null
                   LogLevel ERROR
                   SetEnv CODER_SSH_SESSION_TYPE=JetBrains
-                """.trimIndent().replace("\n", System.lineSeparator())
+                """.trimIndent()
+                    .plus(extraConfig)
+                    .replace("\n", System.lineSeparator())
             })
 
         if (contents == null) {
diff --git a/src/main/kotlin/com/coder/gateway/settings/CoderSettings.kt b/src/main/kotlin/com/coder/gateway/settings/CoderSettings.kt
index 66d17829..949afe7a 100644
--- a/src/main/kotlin/com/coder/gateway/settings/CoderSettings.kt
+++ b/src/main/kotlin/com/coder/gateway/settings/CoderSettings.kt
@@ -14,6 +14,8 @@ import java.nio.file.Files
 import java.nio.file.Path
 import java.nio.file.Paths
 
+const val CODER_SSH_CONFIG_OPTIONS = "CODER_SSH_CONFIG_OPTIONS";
+
 open class CoderSettingsState(
     // Used to download the Coder CLI which is necessary to proxy SSH
     // connections.  The If-None-Match header will be set to the SHA1 of the CLI
@@ -57,6 +59,8 @@ open class CoderSettingsState(
     // around issues on macOS where it periodically wakes and Gateway
     // reconnects, keeping the workspace constantly up.
     open var disableAutostart: Boolean = getOS() == OS.MAC,
+    // Extra SSH config options.
+    open var sshConfigOptions: String = "",
 )
 
 /**
@@ -113,6 +117,12 @@ open class CoderSettings(
     val disableAutostart: Boolean
         get() = state.disableAutostart
 
+    /**
+     * Extra SSH config to append to each host block.
+     */
+    val sshConfigOptions: String
+        get() = state.sshConfigOptions.ifBlank { env.get(CODER_SSH_CONFIG_OPTIONS) }
+
     /**
      * Where the specified deployment should put its data.
      */
diff --git a/src/main/resources/messages/CoderGatewayBundle.properties b/src/main/resources/messages/CoderGatewayBundle.properties
index 4b1a334f..0361e13f 100644
--- a/src/main/resources/messages/CoderGatewayBundle.properties
+++ b/src/main/resources/messages/CoderGatewayBundle.properties
@@ -117,3 +117,9 @@ gateway.connector.settings.disable-autostart.comment=Checking this box will \
   cause the plugin to configure the CLI with --disable-autostart. You must go \
   through the IDE selection again for the plugin to reconfigure the CLI with \
   this setting.
+gateway.connector.settings.ssh-config-options.title=SSH config options
+gateway.connector.settings.ssh-config-options.comment=Extra SSH config options \
+  to use when connecting to a workspace. This text will be appended as-is to \
+  the SSH configuration block for each workspace. If left blank the \
+  environment variable {0} will be used, if set.
+
diff --git a/src/test/fixtures/outputs/extra-config.conf b/src/test/fixtures/outputs/extra-config.conf
new file mode 100644
index 00000000..5dcff2c8
--- /dev/null
+++ b/src/test/fixtures/outputs/extra-config.conf
@@ -0,0 +1,11 @@
+# --- START CODER JETBRAINS test.coder.invalid
+Host coder-jetbrains--extra--test.coder.invalid
+  ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio extra
+  ConnectTimeout 0
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  LogLevel ERROR
+  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
+  ServerAliveInterval 5
+  ServerAliveCountMax 3
+# --- END CODER JETBRAINS test.coder.invalid
diff --git a/src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt b/src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt
index f064578f..a3a7dd26 100644
--- a/src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt
+++ b/src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt
@@ -3,8 +3,10 @@ package com.coder.gateway.cli
 import com.coder.gateway.cli.ex.MissingVersionException
 import com.coder.gateway.cli.ex.ResponseException
 import com.coder.gateway.cli.ex.SSHConfigFormatException
-import com.coder.gateway.settings.CoderSettingsState
+import com.coder.gateway.settings.CODER_SSH_CONFIG_OPTIONS
 import com.coder.gateway.settings.CoderSettings
+import com.coder.gateway.settings.CoderSettingsState
+import com.coder.gateway.settings.Environment
 import com.coder.gateway.util.InvalidVersionException
 import com.coder.gateway.util.OS
 import com.coder.gateway.util.SemVer
@@ -238,34 +240,43 @@ internal class CoderCLIManagerTest {
         val input: String?,
         val output: String,
         val remove: String,
-        val headerCommand: String?,
+        val headerCommand: String = "",
         val disableAutostart: Boolean = false,
-        val features: Features? = null,
+        val features: Features = Features(),
+        val extraConfig: String = "",
+        val env: Environment = Environment(),
     )
 
     @Test
     fun testConfigureSSH() {
+        val extraConfig = listOf(
+            "ServerAliveInterval 5",
+            "ServerAliveCountMax 3").joinToString(System.lineSeparator())
         val tests = listOf(
-            SSHTest(listOf("foo", "bar"), null,"multiple-workspaces", "blank", null),
-            SSHTest(listOf("foo", "bar"), null,"multiple-workspaces", "blank", null),
-            SSHTest(listOf("foo-bar"), "blank", "append-blank", "blank", null),
-            SSHTest(listOf("foo-bar"), "blank-newlines", "append-blank-newlines", "blank", null),
-            SSHTest(listOf("foo-bar"), "existing-end", "replace-end", "no-blocks", null),
-            SSHTest(listOf("foo-bar"), "existing-end-no-newline", "replace-end-no-newline", "no-blocks", null),
-            SSHTest(listOf("foo-bar"), "existing-middle", "replace-middle", "no-blocks", null),
-            SSHTest(listOf("foo-bar"), "existing-middle-and-unrelated", "replace-middle-ignore-unrelated", "no-related-blocks", null),
-            SSHTest(listOf("foo-bar"), "existing-only", "replace-only", "blank", null),
-            SSHTest(listOf("foo-bar"), "existing-start", "replace-start", "no-blocks", null),
-            SSHTest(listOf("foo-bar"), "no-blocks", "append-no-blocks", "no-blocks", null),
-            SSHTest(listOf("foo-bar"), "no-related-blocks", "append-no-related-blocks", "no-related-blocks", null),
-            SSHTest(listOf("foo-bar"), "no-newline", "append-no-newline", "no-blocks", null),
+            SSHTest(listOf("foo", "bar"), null, "multiple-workspaces", "blank"),
+            SSHTest(listOf("foo", "bar"), null, "multiple-workspaces", "blank"),
+            SSHTest(listOf("foo-bar"), "blank", "append-blank", "blank"),
+            SSHTest(listOf("foo-bar"), "blank-newlines", "append-blank-newlines", "blank"),
+            SSHTest(listOf("foo-bar"), "existing-end", "replace-end", "no-blocks"),
+            SSHTest(listOf("foo-bar"), "existing-end-no-newline", "replace-end-no-newline", "no-blocks"),
+            SSHTest(listOf("foo-bar"), "existing-middle", "replace-middle", "no-blocks"),
+            SSHTest(listOf("foo-bar"), "existing-middle-and-unrelated", "replace-middle-ignore-unrelated", "no-related-blocks"),
+            SSHTest(listOf("foo-bar"), "existing-only", "replace-only", "blank"),
+            SSHTest(listOf("foo-bar"), "existing-start", "replace-start", "no-blocks"),
+            SSHTest(listOf("foo-bar"), "no-blocks", "append-no-blocks", "no-blocks"),
+            SSHTest(listOf("foo-bar"), "no-related-blocks", "append-no-related-blocks", "no-related-blocks"),
+            SSHTest(listOf("foo-bar"), "no-newline", "append-no-newline", "no-blocks"),
             if (getOS() == OS.WINDOWS) {
                 SSHTest(listOf("header"), null, "header-command-windows", "blank", """"C:\Program Files\My Header Command\HeaderCommand.exe" --url="%CODER_URL%" --test="foo bar"""")
             } else {
                 SSHTest(listOf("header"), null, "header-command", "blank", "my-header-command --url=\"\$CODER_URL\" --test=\"foo bar\" --literal='\$CODER_URL'")
             },
-            SSHTest(listOf("foo"), null, "disable-autostart", "blank", null, true, Features(true)),
-            SSHTest(listOf("foo"), null, "no-disable-autostart", "blank", null, true, Features(false)),
+            SSHTest(listOf("foo"), null, "disable-autostart", "blank", "", true, Features(true)),
+            SSHTest(listOf("foo"), null, "no-disable-autostart", "blank", "", true, Features(false)),
+            SSHTest(listOf("extra"), null, "extra-config", "blank",
+                extraConfig = extraConfig),
+            SSHTest(listOf("extra"), null, "extra-config", "blank",
+                env = Environment(mapOf(CODER_SSH_CONFIG_OPTIONS to extraConfig))),
         )
 
         val newlineRe = "\r?\n".toRegex()
@@ -274,8 +285,10 @@ internal class CoderCLIManagerTest {
             val settings = CoderSettings(CoderSettingsState(
                 disableAutostart = it.disableAutostart,
                 dataDirectory = tmpdir.resolve("configure-ssh").toString(),
-                headerCommand = it.headerCommand ?: ""),
-                sshConfigPath = tmpdir.resolve(it.input + "_to_" + it.output + ".conf"))
+                headerCommand = it.headerCommand,
+                sshConfigOptions = it.extraConfig),
+                sshConfigPath = tmpdir.resolve(it.input + "_to_" + it.output + ".conf"),
+                env = it.env)
 
             val ccm = CoderCLIManager(URL("https://test.coder.invalid"), settings)
 
@@ -295,12 +308,12 @@ internal class CoderCLIManagerTest {
                 .replace("/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64", escape(ccm.localBinaryPath.toString()))
 
             // Add workspaces.
-            ccm.configSsh(it.workspaces.toSet(), it.features ?: Features())
+            ccm.configSsh(it.workspaces.toSet(), it.features)
 
             assertEquals(expectedConf, settings.sshConfigPath.toFile().readText())
 
             // Remove configuration.
-            ccm.configSsh(emptySet(), it.features ?: Features())
+            ccm.configSsh(emptySet(), it.features)
 
             // Remove is the configuration we expect after removing.
             assertEquals(
diff --git a/src/test/kotlin/com/coder/gateway/settings/CoderSettingsTest.kt b/src/test/kotlin/com/coder/gateway/settings/CoderSettingsTest.kt
index b7873e5e..5c692596 100644
--- a/src/test/kotlin/com/coder/gateway/settings/CoderSettingsTest.kt
+++ b/src/test/kotlin/com/coder/gateway/settings/CoderSettingsTest.kt
@@ -170,6 +170,21 @@ internal class CoderSettingsTest {
         assertEquals(Pair("http://test.gateway.coder.com$expected", "fake-token"), got)
     }
 
+    @Test
+    fun testSSHConfigOptions() {
+        var settings = CoderSettings(CoderSettingsState(sshConfigOptions = "ssh config options from state"))
+        assertEquals("ssh config options from state", settings.sshConfigOptions)
+
+        settings = CoderSettings(CoderSettingsState(),
+            env = Environment(mapOf(CODER_SSH_CONFIG_OPTIONS to "ssh config options from env")))
+        assertEquals("ssh config options from env", settings.sshConfigOptions)
+
+        // State has precedence.
+        settings = CoderSettings(CoderSettingsState(sshConfigOptions = "ssh config options from state"),
+            env = Environment(mapOf(CODER_SSH_CONFIG_OPTIONS to "ssh config options from env")))
+        assertEquals("ssh config options from state", settings.sshConfigOptions)
+    }
+
     @Test
     fun testSettings() {
         // Make sure the remaining settings are being conveyed.