diff --git a/libraries/liblmdb/lmdb.h b/libraries/liblmdb/lmdb.h
index b2525edfeba44a24c302bc19b51e9e045a2a1949..4906472f24d7a120636c1b07650e366eb8a8ce55 100644
--- a/libraries/liblmdb/lmdb.h
+++ b/libraries/liblmdb/lmdb.h
@@ -66,6 +66,7 @@
  *
  *	- A thread can only use one transaction at a time, plus any child
  *	  transactions.  Each transaction belongs to one thread.  See below.
+ *	  The #MDB_NOTLS flag changes this for read-only transactions.
  *
  *	- Use an MDB_env* in the process which opened it, without fork()ing.
  *
@@ -249,6 +250,8 @@ typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *rel
 #define MDB_WRITEMAP		0x80000
 	/** use asynchronous msync when MDB_WRITEMAP is used */
 #define MDB_MAPASYNC		0x100000
+	/** tie reader locktable slots to #MDB_txn objects instead of to threads */
+#define MDB_NOTLS		0x200000
 /** @} */
 
 /**	@defgroup	mdb_dbi_open	Database Flags
@@ -392,8 +395,8 @@ typedef struct MDB_envinfo {
 	size_t	me_mapsize;				/**< Size of the data memory map */
 	size_t	me_last_pgno;			/**< ID of the last used page */
 	size_t	me_last_txnid;			/**< ID of the last committed transaction */
-	unsigned int me_maxreaders;		/**< maximum number of threads for the environment */
-	unsigned int me_numreaders;		/**< maximum number of threads used in the environment */
+	unsigned int me_maxreaders;		/**< max reader slots in the environment */
+	unsigned int me_numreaders;		/**< max reader slots used in the environment */
 } MDB_envinfo;
 
 	/** @brief Return the mdb library version information.
@@ -492,6 +495,15 @@ int  mdb_env_create(MDB_env **env);
 	 *		database or lose the last transactions. Calling #mdb_env_sync()
 	 *		ensures on-disk database integrity until next commit.
 	 *		This flag may be changed at any time using #mdb_env_set_flags().
+	 *	<li>#MDB_NOTLS
+	 *		Don't use Thread-Local Storage. Tie reader locktable slots to
+	 *		#MDB_txn objects instead of to threads. I.e. #mdb_txn_reset() keeps
+	 *		the slot reseved for the #MDB_txn object. A thread may use parallel
+	 *		read-only transactions. A read-only transaction may span threads if
+	 *		the user synchronizes its use. Applications that multiplex many
+	 *		user threads over individual OS threads need this option. Such an
+	 *		application must also serialize the write transactions in an OS
+	 *		thread, since MDB's write locking is unaware of the user threads.
 	 * </ul>
 	 * @param[in] mode The UNIX permissions to set on created files. This parameter
 	 * is ignored on Windows.
@@ -626,13 +638,17 @@ int  mdb_env_get_path(MDB_env *env, const char **path);
 	 */
 int  mdb_env_set_mapsize(MDB_env *env, size_t size);
 
-	/** @brief Set the maximum number of threads for the environment.
+	/** @brief Set the maximum number of threads/reader slots for the environment.
 	 *
 	 * This defines the number of slots in the lock table that is used to track readers in the
 	 * the environment. The default is 126.
+	 * Starting a read-only transaction normally ties a lock table slot to the
+	 * current thread until the environment closes or the thread exits. If
+	 * MDB_NOTLS is in use, #mdb_txn_begin() instead ties the slot to the
+	 * MDB_txn object until it or the #MDB_env object is destroyed.
 	 * This function may only be called after #mdb_env_create() and before #mdb_env_open().
 	 * @param[in] env An environment handle returned by #mdb_env_create()
-	 * @param[in] readers The maximum number of threads
+	 * @param[in] readers The maximum number of reader lock table slots
 	 * @return A non-zero error value on failure and 0 on success. Some possible
 	 * errors are:
 	 * <ul>
@@ -641,7 +657,7 @@ int  mdb_env_set_mapsize(MDB_env *env, size_t size);
 	 */
 int  mdb_env_set_maxreaders(MDB_env *env, unsigned int readers);
 
-	/** @brief Get the maximum number of threads for the environment.
+	/** @brief Get the maximum number of threads/reader slots for the environment.
 	 *
 	 * @param[in] env An environment handle returned by #mdb_env_create()
 	 * @param[out] readers Address of an integer to store the number of readers
@@ -672,8 +688,9 @@ int  mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs);
 	/** @brief Create a transaction for use with the environment.
 	 *
 	 * The transaction handle may be discarded using #mdb_txn_abort() or #mdb_txn_commit().
-	 * @note Transactions may not span threads; a transaction must only be used by a
-	 * single thread. Also, a thread may only have a single transaction.
+	 * @note A transaction and its cursors must only be used by a single
+	 * thread, and a thread may only have a single transaction at a time.
+	 * If #MDB_NOTLS is in use, this does not apply to read-only transactions.
 	 * @note Cursors may not span transactions; each cursor must be opened and closed
 	 * within a single transaction.
 	 * @param[in] env An environment handle returned by #mdb_env_create()
@@ -730,11 +747,13 @@ void mdb_txn_abort(MDB_txn *txn);
 
 	/** @brief Reset a read-only transaction.
 	 *
-	 * This releases the current reader lock but doesn't free the
-	 * transaction handle, allowing it to be used again later by #mdb_txn_renew().
-	 * It otherwise has the same effect as #mdb_txn_abort() but saves some memory
-	 * allocation/deallocation overhead if a thread is going to start a new
-	 * read-only transaction again soon.
+	 * Abort the transaction like #mdb_txn_abort(), but keep the transaction
+	 * handle. #mdb_txn_renew() may reuse the handle. This saves allocation
+	 * overhead if the process will start a new read-only transaction soon,
+	 * and also locking overhead if #MDB_NOTLS is in use. The reader table
+	 * lock is released, but the table slot stays tied to its thread or
+	 * #MDB_txn. Use mdb_txn_abort() to discard a reset handle, and to free
+	 * its lock table slot if MDB_NOTLS is in use.
 	 * All cursors opened within the transaction must be closed before the transaction
 	 * is reset.
 	 * Reader locks generally don't interfere with writers, but they keep old
@@ -1045,8 +1064,8 @@ int  mdb_del(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data);
 
 	/** @brief Create a cursor handle.
 	 *
-	 * Cursors are associated with a specific transaction and database and
-	 * may not span threads.
+	 * A cursor is associated with a specific transaction and database.
+	 * It must be closed before its transaction ends.
 	 * @param[in] txn A transaction handle returned by #mdb_txn_begin()
 	 * @param[in] dbi A database handle returned by #mdb_dbi_open()
 	 * @param[out] cursor Address where the new #MDB_cursor handle will be stored
@@ -1067,8 +1086,9 @@ void mdb_cursor_close(MDB_cursor *cursor);
 
 	/** @brief Renew a cursor handle.
 	 *
-	 * Cursors are associated with a specific transaction and database and
-	 * may not span threads. Cursors that are only used in read-only
+	 * A cursor is associated with a specific transaction and database.
+	 * It must be closed before its transaction ends.
+	 * Cursors that are only used in read-only
 	 * transactions may be re-used, to avoid unnecessary malloc/free overhead.
 	 * The cursor may be associated with a new read-only transaction, and
 	 * referencing the same database handle as it was created with.
diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c
index 471dcd09a43317e511e17c1d4c5509fd3b02d80c..71575d604bf9d08239b2e1b9af18bc3fd57fc8c2 100644
--- a/libraries/liblmdb/mdb.c
+++ b/libraries/liblmdb/mdb.c
@@ -406,6 +406,8 @@ typedef uint16_t	 indx_t;
  *	slot's address is saved in thread-specific data so that subsequent read
  *	transactions started by the same thread need no further locking to proceed.
  *
+ *	If #MDB_NOTLS is set, the slot address is not saved in thread-specific data.
+ *
  *	No reader table is used if the database is on a read-only filesystem.
  *
  *	Since the database uses multi-version concurrency control, readers don't
@@ -1792,7 +1794,8 @@ mdb_txn_renew0(MDB_txn *txn)
 			txn->mt_txnid = env->me_metas[i]->mm_txnid;
 			txn->mt_u.reader = NULL;
 		} else {
-			MDB_reader *r = pthread_getspecific(env->me_txkey);
+			MDB_reader *r = (env->me_flags & MDB_NOTLS) ? txn->mt_u.reader :
+				pthread_getspecific(env->me_txkey);
 			if (r) {
 				if (r->mr_pid != env->me_pid || r->mr_txnid != (txnid_t)-1)
 					return MDB_BAD_RSLOT;
@@ -1816,7 +1819,8 @@ mdb_txn_renew0(MDB_txn *txn)
 				env->me_numreaders = env->me_txns->mti_numreaders;
 				UNLOCK_MUTEX_R(env);
 				r = &env->me_txns->mti_readers[i];
-				if ((rc = pthread_setspecific(env->me_txkey, r)) != 0) {
+				if (!(env->me_flags & MDB_NOTLS) &&
+					(rc = pthread_setspecific(env->me_txkey, r)) != 0) {
 					env->me_txns->mti_readers[i].mr_pid = 0;
 					return rc;
 				}
@@ -2006,7 +2010,8 @@ mdb_txn_reset0(MDB_txn *txn)
 	if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) {
 		if (txn->mt_u.reader) {
 			txn->mt_u.reader->mr_txnid = (txnid_t)-1;
-			txn->mt_u.reader = NULL; /* do not touch mr_txnid again */
+			if (!(env->me_flags & MDB_NOTLS))
+				txn->mt_u.reader = NULL; /* txn does not own reader */
 		}
 		txn->mt_numdbs = 0;	/* mark txn as reset, do not close DBs again */
 	} else {
@@ -2091,6 +2096,10 @@ mdb_txn_abort(MDB_txn *txn)
 		mdb_txn_abort(txn->mt_child);
 
 	mdb_txn_reset0(txn);
+	/* Free reader slot tied to this txn (if MDB_NOTLS && writable FS) */
+	if ((txn->mt_flags & MDB_TXN_RDONLY) && txn->mt_u.reader)
+		txn->mt_u.reader->mr_pid = 0;
+
 	free(txn);
 }
 
@@ -3240,7 +3249,7 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
 			fcntl(env->me_lfd, F_SETFD, fdflags);
 #endif
 
-	{
+	if (!(env->me_flags & MDB_NOTLS)) {
 		rc = pthread_key_create(&env->me_txkey, mdb_env_reader_dest);
 		if (rc)
 			goto fail;
@@ -3418,7 +3427,7 @@ fail:
 	 *	environment and re-opening it with the new flags.
 	 */
 #define	CHANGEABLE	(MDB_NOSYNC|MDB_NOMETASYNC|MDB_MAPASYNC)
-#define	CHANGELESS	(MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY|MDB_WRITEMAP)
+#define	CHANGELESS	(MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY|MDB_WRITEMAP|MDB_NOTLS)
 
 int
 mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode)