diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp
index 75f43a47042f3b2226ce93602b8b55fc492dbf51..4d73c04d076ed565d55404790069653c3147c520 100644
--- a/indra/llcommon/llmutex.cpp
+++ b/indra/llcommon/llmutex.cpp
@@ -32,8 +32,7 @@
 //============================================================================
 
 LLMutex::LLMutex() :
- mCount(0),
- mLockingThread(NO_THREAD)
+ mCount(0)
 {
 }
 
@@ -55,7 +54,7 @@ void LLMutex::lock()
 	
 #if MUTEX_DEBUG
 	// Have to have the lock before we can access the debug info
-	U32 id = LLThread::currentID();
+	auto id = LLThread::currentID();
 	if (mIsLocked[id] != FALSE)
 		LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL;
 	mIsLocked[id] = TRUE;
@@ -74,13 +73,13 @@ void LLMutex::unlock()
 	
 #if MUTEX_DEBUG
 	// Access the debug info while we have the lock
-	U32 id = LLThread::currentID();
+	auto id = LLThread::currentID();
 	if (mIsLocked[id] != TRUE)
 		LL_ERRS() << "Not locked in Thread: " << id << LL_ENDL;	
 	mIsLocked[id] = FALSE;
 #endif
 
-	mLockingThread = NO_THREAD;
+	mLockingThread = LLThread::id_t();
 	mMutex.unlock();
 }
 
@@ -102,7 +101,7 @@ bool LLMutex::isSelfLocked()
 	return mLockingThread == LLThread::currentID();
 }
 
-U32 LLMutex::lockingThread() const
+LLThread::id_t LLMutex::lockingThread() const
 {
 	return mLockingThread;
 }
@@ -122,7 +121,7 @@ bool LLMutex::trylock()
 	
 #if MUTEX_DEBUG
 	// Have to have the lock before we can access the debug info
-	U32 id = LLThread::currentID();
+	auto id = LLThread::currentID();
 	if (mIsLocked[id] != FALSE)
 		LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL;
 	mIsLocked[id] = TRUE;
diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h
index 1a93c048b64d6b84535aeeeb278666fae1b5b07e..838d7d34c069271a4a81a13f4967e439e6eaaf93 100644
--- a/indra/llcommon/llmutex.h
+++ b/indra/llcommon/llmutex.h
@@ -28,6 +28,7 @@
 #define LL_LLMUTEX_H
 
 #include "stdtypes.h"
+#include "llthread.h"
 #include <boost/noncopyable.hpp>
 
 #include "mutex.h"
@@ -44,11 +45,6 @@
 class LL_COMMON_API LLMutex
 {
 public:
-	typedef enum
-	{
-		NO_THREAD = 0xFFFFFFFF
-	} e_locking_thread;
-
 	LLMutex();
 	virtual ~LLMutex();
 	
@@ -57,15 +53,15 @@ class LL_COMMON_API LLMutex
 	void unlock();		// undefined behavior when called on mutex not being held
 	bool isLocked(); 	// non-blocking, but does do a lock/unlock so not free
 	bool isSelfLocked(); //return true if locked in a same thread
-	U32 lockingThread() const; //get ID of locking thread
-	
+	LLThread::id_t lockingThread() const; //get ID of locking thread
+
 protected:
 	std::mutex			mMutex;
 	mutable U32			mCount;
-	mutable U32			mLockingThread;
+	mutable LLThread::id_t	mLockingThread;
 	
 #if MUTEX_DEBUG
-	std::map<U32, BOOL> mIsLocked;
+	std::map<LLThread::id_t, BOOL> mIsLocked;
 #endif
 };
 
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index fb0411d27bfd76c39a8302be87bc67d4c3d483d0..7e4af6ea66a58ca9972583ff29e3060c9ce43269 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -28,9 +28,10 @@
 
 #include <boost/noncopyable.hpp>
 #include <boost/intrusive_ptr.hpp>
-#include "llmutex.h"
 #include "llatomic.h"
 
+class LLMutex;
+
 //----------------------------------------------------------------------------
 // RefCount objects should generally only be accessed by way of LLPointer<>'s
 // see llthread.h for LLThreadSafeRefCount
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index f875e4e0dc35e2bb8deb48f34950e62c080f9ac8..0b9dec969ce0f738684346dc7312018677670360 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -92,21 +92,16 @@ void set_thread_name( DWORD dwThreadID, const char* threadName)
 // }
 // 
 //----------------------------------------------------------------------------
-
-U32 LL_THREAD_LOCAL sThreadID = 0;
-
-U32 LLThread::sIDIter = 0;
-
 namespace
 {
 
-    U32 main_thread()
+    LLThread::id_t main_thread()
     {
         // Using a function-static variable to identify the main thread
         // requires that control reach here from the main thread before it
         // reaches here from any other thread. We simply trust that whichever
         // thread gets here first is the main thread.
-        static U32 s_thread_id = LLThread::currentID();
+        static LLThread::id_t s_thread_id = LLThread::currentID();
         return s_thread_id;
     }
 
@@ -128,10 +123,8 @@ LL_COMMON_API void assert_main_thread()
     }
 }
 
-void LLThread::registerThreadID()
-{
-    sThreadID = ++sIDIter;
-}
+// this function has become moot
+void LLThread::registerThreadID() {}
 
 //
 // Handed to the APR thread creation function
@@ -142,11 +135,12 @@ void LLThread::threadRun()
     set_thread_name(-1, mName.c_str());
 #endif
 
+    // this is the first point at which we're actually running in the new thread
+    mID = currentID();
+
     // for now, hard code all LLThreads to report to single master thread recorder, which is known to be running on main thread
     mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder());
 
-    sThreadID = mID;
-
     // Run the user supplied function
     do 
     {
@@ -188,8 +182,6 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
     mStatus(STOPPED),
     mRecorder(NULL)
 {
-
-    mID = ++sIDIter;
     mRunCondition = new LLCondition();
     mDataLock = new LLMutex();
     mLocalAPRFilePoolp = NULL ;
@@ -367,9 +359,9 @@ void LLThread::setQuitting()
 }
 
 // static
-U32 LLThread::currentID()
+LLThread::id_t LLThread::currentID()
 {
-    return sThreadID;
+    return std::this_thread::get_id();
 }
 
 // static
@@ -396,6 +388,16 @@ void LLThread::wakeLocked()
     }
 }
 
+void LLThread::lockData()
+{
+    mDataLock->lock();
+}
+
+void LLThread::unlockData()
+{
+    mDataLock->unlock();
+}
+
 //============================================================================
 
 //----------------------------------------------------------------------------
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index 37f6e66bbb8f73e2ed593327de1171d778b27e5f..5cd0731f6c9248ea7061b0b9f3939d4149f2cdf7 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -30,7 +30,6 @@
 #include "llapp.h"
 #include "llapr.h"
 #include "boost/intrusive_ptr.hpp"
-#include "llmutex.h"
 #include "llrefcount.h"
 #include <thread>
 
@@ -43,7 +42,6 @@ class LL_COMMON_API LLThread
 {
 private:
     friend class LLMutex;
-    static U32 sIDIter;
 
 public:
     typedef enum e_thread_status
@@ -53,6 +51,7 @@ class LL_COMMON_API LLThread
         QUITTING= 2,    // Someone wants this thread to quit
         CRASHED = -1    // An uncaught exception was thrown by the thread
     } EThreadStatus;
+    typedef std::thread::id id_t;
 
     LLThread(const std::string& name, apr_pool_t *poolp = NULL);
     virtual ~LLThread(); // Warning!  You almost NEVER want to destroy a thread unless it's in the STOPPED state.
@@ -62,7 +61,7 @@ class LL_COMMON_API LLThread
     bool isStopped() const { return (STOPPED == mStatus) || (CRASHED == mStatus); }
     bool isCrashed() const { return (CRASHED == mStatus); } 
     
-    static U32 currentID(); // Return ID of current thread
+    static id_t currentID(); // Return ID of current thread
     static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure.
     
 public:
@@ -86,7 +85,7 @@ class LL_COMMON_API LLThread
 
     LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
 
-    U32 getID() const { return mID; }
+    id_t getID() const { return mID; }
 
     // Called by threads *not* created via LLThread to register some
     // internal state used by LLMutex.  You must call this once early
@@ -107,7 +106,7 @@ class LL_COMMON_API LLThread
 
     std::thread        *mThreadp;
     EThreadStatus       mStatus;
-    U32                 mID;
+    id_t                mID;
     LLTrace::ThreadRecorder* mRecorder;
 
     //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
@@ -124,8 +123,8 @@ class LL_COMMON_API LLThread
     virtual bool runCondition(void);
 
     // Lock/Unlock Run Condition -- use around modification of any variable used in runCondition()
-    inline void lockData();
-    inline void unlockData();
+    void lockData();
+    void unlockData();
     
     // This is the predicate that decides whether the thread should sleep.  
     // It should only be called with mDataLock locked, since the virtual runCondition() function may need to access
@@ -140,17 +139,6 @@ class LL_COMMON_API LLThread
 };
 
 
-void LLThread::lockData()
-{
-    mDataLock->lock();
-}
-
-void LLThread::unlockData()
-{
-    mDataLock->unlock();
-}
-
-
 //============================================================================
 
 // Simple responder for self destructing callbacks
diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp
index 8f33d789ebde25871f9c480d229029507556fbd6..b05630c6b59fbc17a248077f529ac33c6c35d7df 100644
--- a/indra/llcommon/lluuid.cpp
+++ b/indra/llcommon/lluuid.cpp
@@ -43,6 +43,7 @@
 #include "llstring.h"
 #include "lltimer.h"
 #include "llthread.h"
+#include "llmutex.h"
 
 const LLUUID LLUUID::null;
 const LLTransactionID LLTransactionID::tnull;
@@ -738,7 +739,7 @@ void LLUUID::getCurrentTime(uuid_time_t *timestamp)
       getSystemTime(&time_last);
       uuids_this_tick = uuids_per_tick;
       init = TRUE;
-	  mMutex = new LLMutex();
+      mMutex = new LLMutex();
    }
 
    uuid_time_t time_now = {0,0};
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index b1a6f613607c908e505a316dbbd5df8bce5abb31..0387e75c6530107a89957b7470aa0ea986df9dd1 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -34,6 +34,7 @@
 
 #include "llqueuedthread.h"
 #include "llatomic.h"
+#include "llmutex.h"
 
 #define USE_FRAME_CALLBACK_MANAGER 0
 
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp
index 7c93c54cdfc3fba724eddeae0cd6ec2b41773580..e37a38b05f81a1ca1c808d2792f418aa748a261e 100644
--- a/indra/llcorehttp/httpcommon.cpp
+++ b/indra/llcorehttp/httpcommon.cpp
@@ -40,6 +40,7 @@
 #include <sstream>
 #if SAFE_SSL
 #include <openssl/crypto.h>
+#include <functional>               // std::hash
 #endif
 
 
@@ -369,7 +370,8 @@ void ssl_locking_callback(int mode, int type, const char *file, int line)
 //static
 unsigned long ssl_thread_id(void)
 {
-    return LLThread::currentID();
+    // std::thread::id is very deliberately opaque, but we can hash it
+    return std::hash<LLThread::id_t>()(LLThread::currentID());
 }
 #endif
 
diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp
index 1a0eceba0f824144a5fa073f903e68cbbc25c71d..cfe38605ad559988f1948183f644d558b74160bc 100644
--- a/indra/llmessage/llbuffer.cpp
+++ b/indra/llmessage/llbuffer.cpp
@@ -32,6 +32,7 @@
 #include "llmath.h"
 #include "llstl.h"
 #include "llthread.h"
+#include "llmutex.h"
 #include <iterator>
 
 #define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED() llassert(!mMutexp || mMutexp->isSelfLocked())
diff --git a/indra/llmessage/llbufferstream.cpp b/indra/llmessage/llbufferstream.cpp
index ff1c9993cc0e1fc8769fdb12f3104fbcfeb15b0c..39508c1c52e3ee75d069a88aba6913cdca24c7a6 100644
--- a/indra/llmessage/llbufferstream.cpp
+++ b/indra/llmessage/llbufferstream.cpp
@@ -31,6 +31,7 @@
 
 #include "llbuffer.h"
 #include "llthread.h"
+#include "llmutex.h"
 
 static const S32 DEFAULT_OUTPUT_SEGMENT_SIZE = 1024 * 4;
 
diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h
index 87891901ad6935cc627e63f02d03bf22b010de2f..a1ffa9e5d563e782a621a4733d3f0bf41da8d631 100644
--- a/indra/llmessage/llproxy.h
+++ b/indra/llmessage/llproxy.h
@@ -32,6 +32,7 @@
 #include "llmemory.h"
 #include "llsingleton.h"
 #include "llthread.h"
+#include "llmutex.h"
 #include <curl/curl.h>
 #include <string>
 
diff --git a/indra/llplugin/llpluginmessagepipe.h b/indra/llplugin/llpluginmessagepipe.h
index c3498beac04849e37c7ebabd43c9192df1d5ea9f..9d5835eb828fce6252401f650145dd4c040d5af7 100644
--- a/indra/llplugin/llpluginmessagepipe.h
+++ b/indra/llplugin/llpluginmessagepipe.h
@@ -31,6 +31,7 @@
 
 #include "lliosocket.h"
 #include "llthread.h"
+#include "llmutex.h"
 
 class LLPluginMessagePipe;
 
diff --git a/indra/llvfs/llvfs.h b/indra/llvfs/llvfs.h
index dca5ff4ad5f9a3ac88ca32c9006ed573ae328ed4..42feafe20b867a6d37ddd0a3a17b54f4a3c271df 100644
--- a/indra/llvfs/llvfs.h
+++ b/indra/llvfs/llvfs.h
@@ -31,6 +31,7 @@
 #include "lluuid.h"
 #include "llassettype.h"
 #include "llthread.h"
+#include "llmutex.h"
 
 enum EVFSValid 
 {