diff --git a/README.md b/README.md
index dbcde8f8978..f65f5c0e34e 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ If you are using Maven without the BOM, add this to your dependencies:
com.google.cloud
google-cloud-spanner
- 6.110.0
+ 6.111.1
```
@@ -381,6 +381,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/
| List Databases Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ListDatabasesSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/ListDatabasesSample.java) |
| List Instance Config Operations Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigOperationsSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigOperationsSample.java) |
| List Instance Configs Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigsSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigsSample.java) |
+| Mutable Credentials Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/MutableCredentialsExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/MutableCredentialsExample.java) |
| Pg Alter Sequence Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgAlterSequenceSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/PgAlterSequenceSample.java) |
| Pg Async Query To List Async Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgAsyncQueryToListAsyncExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/PgAsyncQueryToListAsyncExample.java) |
| Pg Async Runner Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgAsyncRunnerExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/PgAsyncRunnerExample.java) |
diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml
index a504dc626be..6334cf05ef9 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -33,7 +33,7 @@
com.google.cloud
google-cloud-spanner
- 6.110.0
+ 6.111.1
diff --git a/samples/snippets/src/main/java/com/example/spanner/MutableCredentialsExample.java b/samples/snippets/src/main/java/com/example/spanner/MutableCredentialsExample.java
new file mode 100644
index 00000000000..d0ff08eea6f
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/MutableCredentialsExample.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2026 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner;
+
+// [START spanner_mutable_credentials]
+
+import com.google.auth.oauth2.ServiceAccountCredentials;
+import com.google.cloud.spanner.MutableCredentials;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.FileTime;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+public class MutableCredentialsExample {
+
+ static void createClientWithMutableCredentials() throws IOException {
+ final String credentialsPath = "location_of_service_account_credential_json";
+ Path path = Paths.get(credentialsPath);
+ // Use an array to hold the mutable lastModifiedTime so it can be accessed in the lambda
+ FileTime[] lastModifiedTime = new FileTime[] {Files.getLastModifiedTime(path)};
+
+ // 1 - create service account credentials
+ ServiceAccountCredentials serviceAccountCredentials;
+ try (FileInputStream is = new FileInputStream(credentialsPath)) {
+ serviceAccountCredentials = ServiceAccountCredentials.fromStream(is);
+ }
+
+ // 2 - wrap credentials from step 1 in a MutableCredentials instance
+ MutableCredentials mutableCredentials = new MutableCredentials(serviceAccountCredentials);
+
+ // 3 - set credentials on your SpannerOptions builder to your mutableCredentials
+ SpannerOptions options = SpannerOptions.newBuilder().setCredentials(mutableCredentials).build();
+
+ // 4 - include logic for when/how to update your mutableCredentials
+ // In this example we'll use a SchedulerExecutorService to periodically check for updates
+ ThreadFactory daemonThreadFactory =
+ runnable -> {
+ Thread thread = new Thread(runnable, "spanner-mutable-credentials-rotator");
+ thread.setDaemon(true);
+ return thread;
+ };
+ ScheduledExecutorService executorService =
+ Executors.newSingleThreadScheduledExecutor(daemonThreadFactory);
+ executorService.scheduleAtFixedRate(
+ () -> {
+ try {
+ FileTime currentModifiedTime = Files.getLastModifiedTime(path);
+ if (currentModifiedTime.compareTo(lastModifiedTime[0]) > 0) {
+ lastModifiedTime[0] = currentModifiedTime;
+ try (FileInputStream is = new FileInputStream(credentialsPath)) {
+ ServiceAccountCredentials credentials = ServiceAccountCredentials.fromStream(is);
+ mutableCredentials.updateCredentials(credentials);
+ }
+ }
+ } catch (IOException e) {
+ System.err.println("Failed to check or update credentials: " + e.getMessage());
+ }
+ },
+ 15,
+ 15,
+ TimeUnit.MINUTES);
+
+ // 5. Use the client
+ try (Spanner spanner = options.getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ // Perform operations...
+ // long running client operations will always use the latest credentials wrapped in
+ // mutableCredentials
+ } finally {
+ // Ensure the executor is shut down when the application exits or the client is closed
+ executorService.shutdown();
+ }
+ }
+}
+// [END spanner_mutable_credentials]