diff --git a/buildscripts/resmokeconfig/suites/sharding_hello_failures.yml b/buildscripts/resmokeconfig/suites/sharding_hello_failures.yml
new file mode 100644
index 0000000000..2fca4d40fd
--- /dev/null
+++ b/buildscripts/resmokeconfig/suites/sharding_hello_failures.yml
@@ -0,0 +1,34 @@
+test_kind: fsm_workload_test
+
+selector:
+  roots:
+  - jstests/concurrency/fsm_workloads/*.js
+
+executor:
+  hooks:
+  - class: HelloDelays
+  fixture:
+    class: ShardedClusterFixture
+    mongos_options:
+      set_parameters:
+        enableTestCommands: 1
+        logComponentVerbosity:
+          verbosity: 0
+          command: 1
+          network:
+            verbosity: 1
+            asio: 2
+    mongod_options:
+      set_parameters:
+        enableTestCommands: 1
+        logComponentVerbosity:
+          verbosity: 0
+          command: 1
+          network:
+            verbosity: 1
+            asio: 2
+    enable_sharding:
+    - test
+    num_rs_nodes_per_shard: 3
+    shard_options:
+      all_nodes_electable: true
diff --git a/buildscripts/resmokelib/testing/hooks/hello_failures.py b/buildscripts/resmokelib/testing/hooks/hello_failures.py
new file mode 100644
index 0000000000..746e1a3516
--- /dev/null
+++ b/buildscripts/resmokelib/testing/hooks/hello_failures.py
@@ -0,0 +1,33 @@
+"""Test hook that injects delays into server-side Hello Cmd handler"""
+
+from __future__ import absolute_import
+
+import os
+
+from buildscripts.resmokelib import errors
+from buildscripts.resmokelib import utils
+from buildscripts.resmokelib.testing.hooks import interface
+from buildscripts.resmokelib.testing.fixtures import replicaset
+from buildscripts.resmokelib.testing.fixtures import shardedcluster
+
+from . import interface
+from . import jsfile
+
+class HelloDelays(interface.Hook):
+    """Sets Hello fault injections"""
+
+    def __init__(
+            self, hook_logger, fixture):
+        """Initialize HelloDelays."""
+        description = "Sets Hello fault injections"
+        interface.Hook.__init__(self, hook_logger, fixture, description)
+        self.js_filename = os.path.join("jstests", "hooks", "run_inject_hello_failures.js")
+        self.shell_options = None
+
+    def before_test(self, test, test_report):
+        """Each test will call this before it executes."""
+        print('before_test hook starts injecting Hello failures')
+        hook_test_case = jsfile.DynamicJSTestCase.create_before_test(
+            test.logger, test, self, self.js_filename, self.shell_options)
+        hook_test_case.configure(self.fixture)
+        hook_test_case.run_dynamic_test(test_report)
diff --git a/etc/evergreen.yml b/etc/evergreen.yml
index 8daef762a5..028c2931d9 100644
--- a/etc/evergreen.yml
+++ b/etc/evergreen.yml
@@ -5049,6 +5049,15 @@ tasks:
       resmoke_args: --storageEngine=wiredTiger --shellReadMode=legacy --shellWriteMode=compatibility --excludeWithAnyTags=requires_find_command,requires_timeseries
       fallback_num_sub_suites: 11
 
+- <<: *task_template
+  name: sharding_hello_failures
+  tags: ["sharding", "jscore"]
+  commands:
+  - func: "do setup"
+  - func: "run tests"
+    vars:
+      resmoke_args: --suites=sharding_hello_failures --storageEngine=wiredTiger
+
 - <<: *task_template
   name: sharded_multi_stmt_txn_jscore_passthrough
   tags: ["sharding", "jscore", "multi_stmt"]
diff --git a/jstests/hooks/run_inject_hello_failures.js b/jstests/hooks/run_inject_hello_failures.js
new file mode 100644
index 0000000000..fe2bf0ddc8
--- /dev/null
+++ b/jstests/hooks/run_inject_hello_failures.js
@@ -0,0 +1,137 @@
+'use strict';
+
+// Interval between test loops.
+const kTestLoopPeriodMs = 20 * 1000;
+
+// Sleep injected to the Hello response at the server side.
+const kInjectedHelloDelayMs = 6000 * 1000;
+
+// How many times the fail inject - stepdown cycle is repeated.
+const kTestLoops = 1;
+
+function stepDown(connection) {
+    jsTestLog(`Force stepDown to ${connection}`);
+    const adminDB = connection.getDB('admin');
+    let res;
+    let error;
+    try {
+        res = adminDB.runCommand({replSetStepDown: 10, force: true, secondaryCatchUpPeriodSecs: 8});
+        error = res;
+    } catch (e) {
+        error = e;
+        jsTestLog(`Step down error is usually normal: ${error}`);
+    }
+    if (error && (error.code == undefined || error.code == ErrorCodes.HostUnreachable)) {
+        jsTestLog(`Transient error ${error}`);
+        return;
+    }
+    assert.commandWorked(res);
+    jsTestLog(`Forced stepDown to ${connection}, result ${res}`);
+}
+
+function stepUp(connection) {
+    const adminDB = connection.getDB('admin');
+    assert.soonNoExcept(() => {
+        const res = adminDB.runCommand({replSetStepUp: 1});
+        if (!res.ok) {
+            jsTestLog(`Failed to step up with ${res}`);
+        }
+        return res.ok;
+    }, "Failed to step up", 20000);
+    jsTestLog(`Forced stepUp to ${connection}`);
+}
+
+// The default interval of 30 sec between RSM refresh cycles is too long for
+// this test.
+function injectReduceRefreshPeriod(connection) {
+    jsTestLog(`Reduce refresh interval for ${connection}`);
+    const adminDB = connection.getDB('admin');
+    let res = adminDB.runCommand({
+        configureFailPoint: "modifyReplicaSetMonitorDefaultRefreshPeriod",
+        mode: "alwaysOn",
+        data: {period: 1},
+    });
+    assert.commandWorked(res);
+    res = adminDB.runCommand(
+        {getParameter: 1, "failpoint.modifyReplicaSetMonitorDefaultRefreshPeriod": 1});
+    assert.commandWorked(res);
+    assert.eq(res["failpoint.modifyReplicaSetMonitorDefaultRefreshPeriod"].mode, 1);
+}
+
+function injectHelloFail(connection) {
+    jsTestLog(`Inject Hello fail to connection ${connection}`);
+    const adminDB = connection.getDB('admin');
+    let res = adminDB.runCommand({
+        configureFailPoint: 'waitInHello',
+        mode: "alwaysOn"
+    });
+    assert.commandWorked(res);
+    res = adminDB.runCommand({getParameter: 1, "failpoint.waitInHello": 1});
+    assert.commandWorked(res);
+    assert.eq(res["failpoint.waitInHello"].mode, 1);
+}
+
+function freeze(connection) {
+    const adminDB = connection.getDB('admin');
+    let res = adminDB.runCommand({replSetFreeze: 20});
+    assert.commandWorked(res);
+}
+
+function doFailInjectionLoop(db) {
+    for (let counter = 0; counter < kTestLoops; ++counter) {
+        let connectionsToPrimaries;
+        let connectionsToSecondaries = [];
+        try {
+            connectionsToPrimaries = FixtureHelpers.getPrimaries(db);
+            let allReplicaSets = FixtureHelpers.getAllReplicas(db);
+            for (let replicaSet of allReplicaSets) {
+                connectionsToSecondaries.push(replicaSet.getSecondaries());
+            }
+        } catch (e) {
+            jsTestLog(`Cannot fetch primaries or secondaries: ${e}`);
+            sleep(kTestLoopPeriodMs);
+            continue;
+        }
+        for (let connection of connectionsToPrimaries.concat(FixtureHelpers.getSecondaries(db))) {
+            injectReduceRefreshPeriod(connection);
+        }
+        for (let connection of connectionsToPrimaries) {
+            // Hello fail point will remain blocked after this hook exits.
+            injectHelloFail(connection);
+        }
+        // After fault injection to primary we need to sleep in order to have high
+        // probability that the RSM will get stuck at the primary. Then we
+        // can initiate step down and reproduce the case when the former primary is
+        // highjacking the RSM.
+        sleep(2000);
+        for (let connection of connectionsToPrimaries) {
+            stepDown(connection);
+            freeze(connection);
+        }
+        for (let arrayOfSecondaries of connectionsToSecondaries) {
+            for (let connection of arrayOfSecondaries) {
+                stepUp(connection);
+                break;  // For each replica set pick one secondary.
+            }
+        }
+        sleep(kTestLoopPeriodMs);
+    }
+}
+
+(function() {
+    load('jstests/libs/discover_topology.js');  // For Topology and DiscoverTopology.
+    load('jstests/libs/fixture_helpers.js');
+
+    assert.eq(typeof db, 'object', 'Invalid `db` object, is the shell connected to a mongod?');
+    sleep(2000);
+    var cmdLineOpts = db.adminCommand('getCmdLineOpts');
+    const topology = DiscoverTopology.findConnectedNodes(db.getMongo());
+    jsTestLog(`Run Hello fail injection in ${JSON.stringify(topology)},
+               Invoked with ${JSON.stringify(cmdLineOpts)},
+               topology type ${topology.type}`);
+
+    if (topology.type === Topology.kShardedCluster) {
+        doFailInjectionLoop(db);
+    }
+    jsTestLog(`Hello fail hook completed`);
+})();
diff --git a/jstests/libs/fixture_helpers.js b/jstests/libs/fixture_helpers.js
index ce029d1a4e..ab807c8ad4 100644
--- a/jstests/libs/fixture_helpers.js
+++ b/jstests/libs/fixture_helpers.js
@@ -19,7 +19,7 @@ var FixtureHelpers = (function() {
      * Returns an array of connections to each data-bearing replica set in the fixture (not
      * including the config servers).
      */
-    function _getAllReplicas(db) {
+    function getAllReplicas(db) {
         let replicas = [];
         if (isMongos(db)) {
             const shardObjs = db.getSiblingDB("config").shards.find().sort({_id: 1});
@@ -36,7 +36,7 @@ var FixtureHelpers = (function() {
      * Asserts if the fixture is a standalone or if the shards are standalones.
      */
     function awaitReplication(db) {
-        _getAllReplicas(db).forEach((replSet) => replSet.awaitReplication());
+        getAllReplicas(db).forEach((replSet) => replSet.awaitReplication());
     }
 
     /**
@@ -47,7 +47,7 @@ var FixtureHelpers = (function() {
      * Asserts if the fixture is a standalone or if the shards are standalones.
      */
     function awaitLastOpCommitted(db) {
-        _getAllReplicas(db).forEach((replSet) => replSet.awaitLastOpCommitted());
+        getAllReplicas(db).forEach((replSet) => replSet.awaitLastOpCommitted());
     }
 
     /**
@@ -155,6 +155,22 @@ var FixtureHelpers = (function() {
         return shardConn;
     }
 
+    /**
+     * Returns a collection of connections to each primary in a cluster.
+     */
+    function getPrimaries(db) {
+        return getAllReplicas(db).map((replSet) => replSet.getPrimary());
+    }
+
+    /**
+     * Returns a collection of connections to secondaries in a cluster.
+     */
+    function getSecondaries(db) {
+        return getAllReplicas(db).reduce((array, replSet) => {
+            return array.concat(replSet.getSecondaries());
+        }, []);
+    }
+
     /**
      * Returns true if we have a replica set.
      */
@@ -172,6 +188,9 @@ var FixtureHelpers = (function() {
         awaitLastOpCommitted: awaitLastOpCommitted,
         mapOnEachPrimary: mapOnEachPrimary,
         runCommandOnEachPrimary: runCommandOnEachPrimary,
+        getAllReplicas: getAllReplicas,
+        getPrimaries: getPrimaries,
+        getSecondaries: getSecondaries,
         getPrimaryForNodeHostingDatabase: getPrimaryForNodeHostingDatabase,
         isReplSet: isReplSet,
     };
