diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 7d07d0c3a7f3b53824988ada4ade8c3fda5d3f79..e15cea9ef260b4db3404a4a5bc9f8320e10f31d2 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -92,7 +92,10 @@ class LLSD::Impl
 public:
 	static void reset(Impl*& var, Impl* impl);
 		///< safely set var to refer to the new impl (possibly shared)
-		
+
+    static void move(Impl*& var, Impl*& impl);
+        ///< safely move impl from one object to another
+
 	static       Impl& safe(      Impl*);
 	static const Impl& safe(const Impl*);
 		///< since a NULL Impl* is used for undefined, this ensures there is
@@ -664,15 +667,30 @@ LLSD::Impl::~Impl()
 
 void LLSD::Impl::reset(Impl*& var, Impl* impl)
 {
-	if (impl && impl->mUseCount != STATIC_USAGE_COUNT) 
+	if (var != impl)
 	{
-		++impl->mUseCount;
+		if (impl && impl->mUseCount != STATIC_USAGE_COUNT)
+		{
+			++impl->mUseCount;
+		}
+		if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0)
+		{
+			delete var;
+		}
+		var = impl;
 	}
-	if (var  &&  var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0)
+}
+
+void LLSD::Impl::move(Impl*& var, Impl*& impl)
+{
+	if (var == impl) return; // Bail out var is impl
+
+	if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0)
 	{
-		delete var;
+		delete var; // destroy var if usage falls to 0 and not static
 	}
-	var = impl;
+	var = impl; // Steal impl to var without incrementing use since this is a move
+	impl = nullptr; // null out old-impl pointer
 }
 
 LLSD::Impl& LLSD::Impl::safe(Impl* impl)
@@ -824,6 +842,8 @@ LLSD::~LLSD()							{ FREE_LLSD_OBJECT; Impl::reset(impl, nullptr); }
 LLSD::LLSD(const LLSD& other) : impl(nullptr) { ALLOC_LLSD_OBJECT;  assign(other); }
 void LLSD::assign(const LLSD& other)	{ Impl::assign(impl, other.impl); }
 
+LLSD::LLSD(LLSD&& other) noexcept : impl(nullptr) { ALLOC_LLSD_OBJECT;  Impl::move(impl, other.impl); }
+LLSD& LLSD::operator=(LLSD&& other) noexcept { Impl::move(impl, other.impl); return *this; }
 
 void LLSD::clear()						{ Impl::assignUndefined(impl); }
 
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index 24f72e4302f50d4d70024981d4497eec12a085b1..30ef6a8bdeb159765144d9d1c56503524e094a66 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -147,7 +147,7 @@
 // Normally undefined, used for diagnostics
 //#define LLSD_DEBUG_INFO	1
 
-class LL_COMMON_API LLSD
+class LL_COMMON_API LLSD final
 {
 public:
 		LLSD();		///< initially Undefined
@@ -161,6 +161,12 @@ class LL_COMMON_API LLSD
 
 	//@}
 
+    /** @name Movable */
+    //@{
+        LLSD(LLSD&& other) noexcept;
+        LLSD& operator=(LLSD&& other) noexcept;
+    //@}
+
 	void clear();	///< resets to Undefined
 
 
@@ -389,9 +395,9 @@ class LL_COMMON_API LLSD
 		using an arbitrary pointer or scalar type to std::string.
 	 */
 	//@{
-		LLSD(const void*);				///< construct from aribrary pointers
-		void assign(const void*);		///< assign from arbitrary pointers
-		LLSD& operator=(const void*);	///< assign from arbitrary pointers
+		LLSD(const void*) = delete;				///< construct from aribrary pointers
+		void assign(const void*) = delete;		///< assign from arbitrary pointers
+		LLSD& operator=(const void*) = delete;	///< assign from arbitrary pointers
 		
 		bool has(Integer) const;		///< has() only works for Maps
 	//@}