diff --git a/src/mongo/db/concurrency/lock_manager_defs.h b/src/mongo/db/concurrency/lock_manager_defs.h
index 7234e4ba910..9c5f978d220 100644
--- a/src/mongo/db/concurrency/lock_manager_defs.h
+++ b/src/mongo/db/concurrency/lock_manager_defs.h
@@ -273,8 +273,8 @@ public:
     }
 
     // This defines the canonical locking order, first by type and then hash id
-    bool operator<(const ResourceId& rhs) const {
-        return _fullHash < rhs._fullHash;
+    auto operator<=>(const ResourceId& rhs) const {
+        return _fullHash <=> rhs._fullHash;
     }
 
     ResourceType getType() const {
diff --git a/src/mongo/db/concurrency/locker.cpp b/src/mongo/db/concurrency/locker.cpp
index d733e043fe1..04cb0100681 100644
--- a/src/mongo/db/concurrency/locker.cpp
+++ b/src/mongo/db/concurrency/locker.cpp
@@ -48,6 +48,10 @@
 namespace mongo {
 namespace {
 
+bool canPotentiallyDeadlock(OperationContext* opCtx, const Date_t& deadline) {
+    return opCtx->uninterruptibleLocksRequested_DO_NOT_USE() || deadline == Date_t::max();
+}
+
 // Ignore data races in certain functions when running with TSAN. For performance reasons,
 // diagnostic commands are expected to race with concurrent lock acquisitions while gathering
 // statistics.
@@ -294,7 +298,8 @@ void Locker::lockGlobal(OperationContext* opCtx, LockMode mode, Date_t deadline)
             "requested"_attr = modeName(mode));
     }
 
-    const LockResult result = _lockBegin(opCtx, resourceIdGlobal, mode);
+    const LockResult result =
+        _lockBegin(opCtx, resourceIdGlobal, mode, canPotentiallyDeadlock(opCtx, deadline));
     // Fast, uncontended path
     if (result == LOCK_OK)
         return;
@@ -324,6 +329,10 @@ bool Locker::unlockGlobal() {
         }
     }
 
+    // As we no loinger hold any locks we reset the last locked state. This allows us to reuse the
+    // locker after releasing everything.
+    _lastLockedResource = {};
+
     return true;
 }
 
@@ -335,7 +344,7 @@ LockResult Locker::lockRSTLBegin(OperationContext* opCtx, LockMode mode) {
     }
 
     invariant(testOnly || mode == MODE_IX || mode == MODE_X);
-    return _lockBegin(opCtx, resourceIdReplicationStateTransitionLock, mode);
+    return _lockBegin(opCtx, resourceIdReplicationStateTransitionLock, mode, false);
 }
 
 void Locker::lockRSTLComplete(OperationContext* opCtx,
@@ -370,7 +379,8 @@ void Locker::lock(OperationContext* opCtx, ResourceId resId, LockMode mode, Date
     // `lockGlobal` must be called to lock `resourceIdGlobal`.
     invariant(resId != resourceIdGlobal);
 
-    const LockResult result = _lockBegin(opCtx, resId, mode);
+    const LockResult result =
+        _lockBegin(opCtx, resId, mode, canPotentiallyDeadlock(opCtx, deadline));
 
     // Fast, uncontended path
     if (result == LOCK_OK)
@@ -778,7 +788,10 @@ void Locker::dump() const {
 }
 
 MONGO_TSAN_IGNORE
-LockResult Locker::_lockBegin(OperationContext* opCtx, ResourceId resId, LockMode mode) {
+LockResult Locker::_lockBegin(OperationContext* opCtx,
+                              ResourceId resId,
+                              LockMode mode,
+                              bool canPotentiallyDeadlock) {
     dassert(!getWaitingResource().isValid());
 
     // Operations which are holding open an oplog hole cannot block when acquiring locks.
@@ -845,6 +858,16 @@ LockResult Locker::_lockBegin(OperationContext* opCtx, ResourceId resId, LockMod
     // otherwise we might reset state if the lock becomes granted very fast.
     _notify.clear();
 
+    // If this is the first request make sure that the ordering is correct. Otherwise we risk
+    // deadlocking the server due to the wrong lock order acquisition.
+    if (canPotentiallyDeadlock && (_modeForTicket == MODE_IS || _modeForTicket == MODE_IX) &&
+        request->recursiveCount == 1 && resType == RESOURCE_GLOBAL) {
+
+        auto& lockAcquired = _lastLockedResource[resType];
+        invariant(lockAcquired <= resId, "attempted to lock out of order");
+        lockAcquired = resId;
+    }
+
     auto result = request->recursiveCount == 1 ? _lockManager->lock(resId, request, mode) : LOCK_OK;
 
     if (result == LOCK_WAITING) {
diff --git a/src/mongo/db/concurrency/locker.h b/src/mongo/db/concurrency/locker.h
index 5cb737e7ed5..e03013742ea 100644
--- a/src/mongo/db/concurrency/locker.h
+++ b/src/mongo/db/concurrency/locker.h
@@ -567,7 +567,7 @@ public:
     }
 
     LockResult lockBeginForTest(OperationContext* opCtx, ResourceId resId, LockMode mode) {
-        return _lockBegin(opCtx, resId, mode);
+        return _lockBegin(opCtx, resId, mode, false);
     }
 
     void lockCompleteForTest(OperationContext* opCtx,
@@ -609,7 +609,7 @@ protected:
      * NOTE: These methods are not public and should only be used inside the class
      * implementation and for unit-tests and not called directly.
      */
-    LockResult _lockBegin(OperationContext* opCtx, ResourceId resId, LockMode mode);
+    LockResult _lockBegin(OperationContext* opCtx, ResourceId resId, LockMode mode, bool canPotentiallyDeadlock);
 
     /**
      * Waits for the completion of a lock, previously requested through _lockBegin/
@@ -769,6 +769,10 @@ protected:
     // If isValid(), the ResourceId of the resource currently waiting for the lock. If not valid,
     // there is no resource currently waiting.
     ResourceId _waitingResource;
+
+    // Tracks the last ResourceId used for locking. This prevents any lock ordering issues with
+    // nested locks.
+    std::array<ResourceId, ResourceType::ResourceTypesCount> _lastLockedResource;
 };
 
 /**

