diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
index 972a2fa6..35252e3a 100644
--- a/include/libcamera/internal/pipeline_handler.h
+++ b/include/libcamera/internal/pipeline_handler.h
@@ -88,7 +88,7 @@ private:
 	void mediaDeviceDisconnected(MediaDevice *media);
 	virtual void disconnect();
 
-	void doQueueRequest(Request *request);
+	int doQueueRequest(Request *request);
 	void doQueueRequests();
 
 	std::vector<std::shared_ptr<MediaDevice>> mediaDevices_;
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index d84dff3c..2ce093ff 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -452,8 +452,10 @@ void PipelineHandler::queueRequest(Request *request)
 /**
  * \brief Queue one requests to the device
  */
-void PipelineHandler::doQueueRequest(Request *request)
+int PipelineHandler::doQueueRequest(Request *request)
 {
+	int ret;
+
 	LIBCAMERA_TRACEPOINT(request_device_queue, request);
 
 	Camera *camera = request->_d()->camera();
@@ -464,12 +466,14 @@ void PipelineHandler::doQueueRequest(Request *request)
 
 	if (request->_d()->cancelled_) {
 		completeRequest(request);
-		return;
+		return -ECANCELED;
 	}
 
-	int ret = queueRequestDevice(camera, request);
-	if (ret)
+	ret = queueRequestDevice(camera, request);
+	if (ret && ret != -EAGAIN)
 		cancelRequest(request);
+
+	return ret;
 }
 
 /**
@@ -485,7 +489,9 @@ void PipelineHandler::doQueueRequests()
 		if (!request->_d()->prepared_)
 			break;
 
-		doQueueRequest(request);
+		if (doQueueRequest(request) == -EAGAIN)
+			break;
+
 		waitingRequests_.pop();
 	}
 }
@@ -502,6 +508,10 @@ void PipelineHandler::doQueueRequests()
  * parameters will be applied to the frames captured in the buffers provided in
  * the request.
  *
+ * If the underlying hardware pipeline is saturated with requests, this
+ * function returns -EAGAIN, so that the \a request stays in the internal
+ * waiting queue.
+ *
  * \context This function is called from the CameraManager thread.
  *
  * \return 0 on success or a negative error code otherwise
