diff --git a/libraries/libmdb/mdb.c b/libraries/libmdb/mdb.c
index 8c0046c07a8311c8983a6b1c353ecf9abb0d28f8..7129d0a1bc0ba55ab6117e41671ac57a9999c8e2 100644
--- a/libraries/libmdb/mdb.c
+++ b/libraries/libmdb/mdb.c
@@ -1924,6 +1924,7 @@ mdb_txn_commit(MDB_txn *txn)
 	}
 
 	/* save to free list */
+free2:
 	freecnt = txn->mt_free_pgs[0];
 	if (!MDB_IDL_IS_ZERO(txn->mt_free_pgs)) {
 		MDB_val key, data;
@@ -1962,8 +1963,6 @@ mdb_txn_commit(MDB_txn *txn)
 				return rc;
 			}
 		} while (freecnt != txn->mt_free_pgs[0]);
-		if (mdb_midl_shrink(&txn->mt_free_pgs))
-			env->me_free_pgs = txn->mt_free_pgs;
 	}
 	/* should only be one record now */
 again:
@@ -1980,6 +1979,9 @@ again:
 		data.mv_size = MDB_IDL_SIZEOF(mop->mo_pages);
 		data.mv_data = mop->mo_pages;
 		orig = mop->mo_pages[0];
+		/* These steps may grow the freelist again
+		 * due to freed overflow pages...
+		 */
 		mdb_cursor_put(&mc, &key, &data, 0);
 		if (mop == env->me_pghead) {
 			/* could have been used again here */
@@ -2000,6 +2002,14 @@ again:
 		env->me_pgfirst = 0;
 		env->me_pglast = 0;
 	}
+	/* Check for growth of freelist again */
+	if (freecnt != txn->mt_free_pgs[0])
+		goto free2;
+
+	if (!MDB_IDL_IS_ZERO(txn->mt_free_pgs)) {
+		if (mdb_midl_shrink(&txn->mt_free_pgs))
+			env->me_free_pgs = txn->mt_free_pgs;
+	}
 
 	/* Update DB root pointers. Their pages have already been
 	 * touched so this is all in-place and cannot fail.
@@ -4314,9 +4324,42 @@ more:
 			goto put_sub;
 		}
 current:
-		/* same size, just replace it */
-		if (!F_ISSET(leaf->mn_flags, F_BIGDATA) &&
-			NODEDSZ(leaf) == data->mv_size) {
+		/* overflow page overwrites need special handling */
+		if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
+			MDB_page *omp;
+			pgno_t pg;
+			int ovpages, dpages;
+
+			ovpages = OVPAGES(NODEDSZ(leaf), mc->mc_txn->mt_env->me_psize);
+			dpages = OVPAGES(data->mv_size, mc->mc_txn->mt_env->me_psize);
+			memcpy(&pg, NODEDATA(leaf), sizeof(pg));
+			mdb_page_get(mc->mc_txn, pg, &omp);
+			/* Is the ov page writable and large enough? */
+			if ((omp->mp_flags & P_DIRTY) && ovpages >= dpages) {
+				/* yes, overwrite it. Note in this case we don't
+				 * bother to try shrinking the node if the new data
+				 * is smaller than the overflow threshold.
+				 */
+				if (F_ISSET(flags, MDB_RESERVE))
+					data->mv_data = METADATA(omp);
+				else
+					memcpy(METADATA(omp), data->mv_data, data->mv_size);
+				goto done;
+			} else {
+				/* no, free ovpages */
+				int i;
+				mc->mc_db->md_overflow_pages -= ovpages;
+				for (i=0; i<ovpages; i++) {
+					DPRINTF("freed ov page %zu", pg);
+					mdb_midl_append(&mc->mc_txn->mt_free_pgs, pg);
+					pg++;
+				}
+			}
+		} else if (NODEDSZ(leaf) == data->mv_size) {
+			/* same size, just replace it. Note that we could
+			 * also reuse this node if the new data is smaller,
+			 * but instead we opt to shrink the node in that case.
+			 */
 			if (F_ISSET(flags, MDB_RESERVE))
 				data->mv_data = NODEDATA(leaf);
 			else