diff --git a/core/modules/workspace/src/Negotiator/QueryParameterWorkspaceNegotiator.php b/core/modules/workspace/src/Negotiator/QueryParameterWorkspaceNegotiator.php
new file mode 100644
index 0000000000000000000000000000000000000000..0797035a433dd19d7ef21602af94492298898e87
--- /dev/null
+++ b/core/modules/workspace/src/Negotiator/QueryParameterWorkspaceNegotiator.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\workspace\Negotiator;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Defines the query parameter workspace negotiator.
+ */
+class QueryParameterWorkspaceNegotiator extends SessionWorkspaceNegotiator {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applies(Request $request) {
+    return is_string($request->query->get('workspace')) && parent::applies($request);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getActiveWorkspace(Request $request) {
+    $workspace_id = $request->query->get('workspace');
+
+    if ($workspace_id && ($workspace = $this->workspaceStorage->load($workspace_id))) {
+      $this->setActiveWorkspace($workspace);
+      return $workspace;
+    }
+
+    return NULL;
+  }
+
+}
diff --git a/core/modules/workspace/tests/src/Functional/WorkspaceSwitcherTest.php b/core/modules/workspace/tests/src/Functional/WorkspaceSwitcherTest.php
index ede23825a8b7e6c198580233c853dec7c4023de7..22a51b33c2d7ff6538ad03ac4a576ec85240bd9c 100644
--- a/core/modules/workspace/tests/src/Functional/WorkspaceSwitcherTest.php
+++ b/core/modules/workspace/tests/src/Functional/WorkspaceSwitcherTest.php
@@ -19,9 +19,11 @@ class WorkspaceSwitcherTest extends BrowserTestBase {
   public static $modules = ['block', 'workspace'];
 
   /**
-   * Test switching workspace via the switcher block and admin page.
+   * {@inheritdoc}
    */
-  public function testSwitchingWorkspaces() {
+  protected function setUp() {
+    parent::setUp();
+
     $permissions = [
       'create workspace',
       'edit own workspace',
@@ -33,7 +35,12 @@ public function testSwitchingWorkspaces() {
 
     $mayer = $this->drupalCreateUser($permissions);
     $this->drupalLogin($mayer);
+  }
 
+  /**
+   * Test switching workspace via the switcher block and admin page.
+   */
+  public function testSwitchingWorkspaces() {
     $vultures = $this->createWorkspaceThroughUi('Vultures', 'vultures');
     $this->switchToWorkspace($vultures);
 
@@ -48,4 +55,21 @@ public function testSwitchingWorkspaces() {
     $page->findLink($gravity->label());
   }
 
+  /**
+   * Test switching workspace via a query parameter.
+   */
+  public function testQueryParameterNegotiator() {
+    $web_assert = $this->assertSession();
+    // Initially the default workspace should be active.
+    $web_assert->elementContains('css', '.block-workspace-switcher', 'Live');
+
+    // When adding a query parameter the workspace will be switched.
+    $this->drupalGet('<front>', ['query' => ['workspace' => 'stage']]);
+    $web_assert->elementContains('css', '.block-workspace-switcher', 'Stage');
+
+    // The workspace switching via query parameter should persist.
+    $this->drupalGet('<front>');
+    $web_assert->elementContains('css', '.block-workspace-switcher', 'Stage');
+  }
+
 }
diff --git a/core/modules/workspace/workspace.services.yml b/core/modules/workspace/workspace.services.yml
index 13d67aee5b6a463532cfd0c17485045788ac8d96..cd2b9ea51de09d251ae0b6d2693b1f68ac024682 100644
--- a/core/modules/workspace/workspace.services.yml
+++ b/core/modules/workspace/workspace.services.yml
@@ -15,6 +15,11 @@ services:
   workspace.negotiator.session:
     class: Drupal\workspace\Negotiator\SessionWorkspaceNegotiator
     arguments: ['@current_user', '@session', '@entity_type.manager']
+    tags:
+      - { name: workspace_negotiator, priority: 50 }
+  workspace.negotiator.query_parameter:
+    class: Drupal\workspace\Negotiator\QueryParameterWorkspaceNegotiator
+    parent: workspace.negotiator.session
     tags:
       - { name: workspace_negotiator, priority: 100 }
   cache_context.workspace: