diff --git a/changelogs/unreleased/gh-9995-vy-scheduler-crash-fix.md b/changelogs/unreleased/gh-9995-vy-scheduler-crash-fix.md
new file mode 100644
index 0000000000000000000000000000000000000000..f8ffbff55667aed9a3309f780fd0235a9b838a26
--- /dev/null
+++ b/changelogs/unreleased/gh-9995-vy-scheduler-crash-fix.md
@@ -0,0 +1,4 @@
+## bugfix/vinyl
+
+* Fixed a use-after-free bug in the compaction scheduler triggered by a race
+  with a concurrent DDL operation (gh-9995).
diff --git a/src/box/vy_scheduler.c b/src/box/vy_scheduler.c
index daddff071cef4b75664b69af8cb092159c7c6a6e..ea9b438bdb7a7c3f3ce4778898ba18cd3cba7380 100644
--- a/src/box/vy_scheduler.c
+++ b/src/box/vy_scheduler.c
@@ -1839,6 +1839,11 @@ vy_scheduler_peek_dump(struct vy_scheduler *scheduler, struct vy_task **ptask)
 	}
 	if (!lsm->is_dumping && lsm->pin_count == 0 &&
 	    vy_lsm_generation(lsm) == scheduler->dump_generation) {
+		/*
+		 * The code below may yield. Take a reference to the LSM tree
+		 * to make sure it isn't deleted in the meantime.
+		 */
+		vy_lsm_ref(lsm);
 		/*
 		 * Dump is in progress and there is an LSM tree that
 		 * contains data that must be dumped at the current
@@ -1846,13 +1851,17 @@ vy_scheduler_peek_dump(struct vy_scheduler *scheduler, struct vy_task **ptask)
 		 */
 		if (worker == NULL) {
 			worker = vy_worker_pool_get(&scheduler->dump_pool);
-			if (worker == NULL)
+			if (worker == NULL) {
+				vy_lsm_unref(lsm);
 				return 0; /* all workers are busy */
+			}
 		}
 		if (vy_task_dump_new(scheduler, worker, lsm, ptask) != 0) {
 			vy_worker_pool_put(worker);
+			vy_lsm_unref(lsm);
 			return -1;
 		}
+		vy_lsm_unref(lsm);
 		if (*ptask != NULL)
 			return 0; /* new task */
 		/*
@@ -1909,15 +1918,24 @@ vy_scheduler_peek_compaction(struct vy_scheduler *scheduler,
 		goto no_task; /* nothing to do */
 	if (vy_lsm_compaction_priority(lsm) <= 1)
 		goto no_task; /* nothing to do */
+	/*
+	 * The code below may yield. Take a reference to the LSM tree
+	 * to make sure it isn't deleted in the meantime.
+	 */
+	vy_lsm_ref(lsm);
 	if (worker == NULL) {
 		worker = vy_worker_pool_get(&scheduler->compaction_pool);
-		if (worker == NULL)
+		if (worker == NULL) {
+			vy_lsm_unref(lsm);
 			return 0; /* all workers are busy */
+		}
 	}
 	if (vy_task_compaction_new(scheduler, worker, lsm, ptask) != 0) {
 		vy_worker_pool_put(worker);
+		vy_lsm_unref(lsm);
 		return -1;
 	}
+	vy_lsm_unref(lsm);
 	if (*ptask == NULL)
 		goto retry; /* LSM tree dropped or range split/coalesced */
 	return 0; /* new task */