diff --git a/docs/source/format/FlightSql.rst b/docs/source/format/FlightSql.rst
index 6bb917271366..5573c0040761 100644
--- a/docs/source/format/FlightSql.rst
+++ b/docs/source/format/FlightSql.rst
@@ -141,6 +141,21 @@ the ``type`` should be ``ClosePreparedStatement``).
Execute a previously created prepared statement and get the results.
When used with DoPut: binds parameter values to the prepared statement.
+ The server may optionally provide an updated handle in the response.
+ Updating the handle allows the client to supply all state required to
+ execute the query in an ActionPreparedStatementExecute message.
+ For example, stateless servers can encode the bound parameter values into
+ the new handle, and the client will send that new handle with parameters
+ back to the server.
+
+ Note that a handle returned from a DoPut call with
+ CommandPreparedStatementQuery can itself be passed to a subsequent DoPut
+ call with CommandPreparedStatementQuery to bind a new set of parameters.
+ The subsequent call itself may return an updated handle which again should
+ be used for subsequent requests.
+
+ The server is responsible for detecting the case where the client does not
+ use the updated handle and should return an error.
When used with GetFlightInfo: execute the prepared statement. The
prepared statement can be reused after fetching results.
diff --git a/docs/source/format/FlightSql/CommandPreparedStatementQuery.mmd b/docs/source/format/FlightSql/CommandPreparedStatementQuery.mmd
index cb50522eb5a3..cbd1eb6014bc 100644
--- a/docs/source/format/FlightSql/CommandPreparedStatementQuery.mmd
+++ b/docs/source/format/FlightSql/CommandPreparedStatementQuery.mmd
@@ -28,6 +28,8 @@ Server->>Client: ActionCreatePreparedStatementResult{handle}
loop for each invocation of the prepared statement
Client->>Server: DoPut(CommandPreparedStatementQuery)
Client->>Server: stream of FlightData
+Server-->>Client: DoPutPreparedStatementResult{handle}
+Note over Client,Server: optional response with updated handle
Client->>Server: GetFlightInfo(CommandPreparedStatementQuery)
Server->>Client: FlightInfo{endpoints: [FlightEndpoint{…}, …]}
loop for each endpoint in FlightInfo.endpoints
diff --git a/docs/source/format/FlightSql/CommandPreparedStatementQuery.mmd.svg b/docs/source/format/FlightSql/CommandPreparedStatementQuery.mmd.svg
index 96a5bc368829..cbf6a78e9a5c 100644
--- a/docs/source/format/FlightSql/CommandPreparedStatementQuery.mmd.svg
+++ b/docs/source/format/FlightSql/CommandPreparedStatementQuery.mmd.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/format/FlightSql.proto b/format/FlightSql.proto
index 581cf1f76d57..3282ee4f4730 100644
--- a/format/FlightSql.proto
+++ b/format/FlightSql.proto
@@ -1797,6 +1797,26 @@ message DoPutUpdateResult {
int64 record_count = 1;
}
+/* An *optional* response returned when `DoPut` is called with `CommandPreparedStatementQuery`.
+ *
+ * *Note on legacy behavior*: previous versions of the protocol did not return any result for
+ * this command, and that behavior should still be supported by clients. In that case, the client
+ * can continue as though the fields in this message were not provided or set to sensible default values.
+ */
+message DoPutPreparedStatementResult {
+ option (experimental) = true;
+
+ // Represents a (potentially updated) opaque handle for the prepared statement on the server.
+ // Because the handle could potentially be updated, any previous handles for this prepared
+ // statement should be considered invalid, and all subsequent requests for this prepared
+ // statement must use this new handle.
+ // The updated handle allows implementing query parameters with stateless services.
+ //
+ // When an updated handle is not provided by the server, clients should contiue
+ // using the previous handle provided by `ActionCreatePreparedStatementResonse`.
+ optional bytes prepared_statement_handle = 1;
+}
+
/*
* Request message for the "CancelQuery" action.
*