diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 2dc18e6..6829d52 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -7352,6 +7352,14 @@ typedef struct
        On failure this function should set the error message
        with <function>PGsetRowProcessorErrMsg</function> if the cause
        is other than out of memory.
+       When non-blocking API is in use, it can also return 2
+       for early exit from <function>PQisBusy</function> function.
+       The supplied <parameter>res</parameter> and <parameter>columns</parameter>
+       values will stay valid so row can be processed outside of callback.
+       Caller is resposible for tracking whether the <parameter>PQisBusy</parameter>
+       returned early from callback or for other reasons.
+       Usually this should happen via setting cached values to NULL
+       before calling <function>PQisBusy</function>.
      </para>
 
      <para>
diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c
index 7498580..ae4d7b0 100644
--- a/src/interfaces/libpq/fe-protocol2.c
+++ b/src/interfaces/libpq/fe-protocol2.c
@@ -820,6 +820,9 @@ getAnotherTuple(PGconn *conn, bool binary)
 	rp= conn->rowProcessor(result, conn->rowProcessorParam, rowbuf);
 	if (rp == 1)
 		return 0;
+	else if (rp == 2 && pqIsnonblocking(conn))
+		/* processor requested early exit */
+		return EOF;
 	else if (rp != 0)
 		PQsetRowProcessorErrMsg(result, libpq_gettext("invalid return value from row processor\n"));
 
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index a67e3ac..0260ba6 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -697,6 +697,11 @@ getAnotherTuple(PGconn *conn, int msgLength)
 		/* everything is good */
 		return 0;
 	}
+	if (rp == 2 && pqIsnonblocking(conn))
+	{
+		/* processor requested early exit */
+		return EOF;
+	}
 
 	/* there was some problem */
 	if (rp == 0)
