A RestTemplate connect timeout limits how long the client waits to establish a connection; a read timeout limits a wait for response data after a connection exists. An outbound call can otherwise occupy a request thread longer than the application expects when a remote service is slow or unreachable. Configure both limits for the service you call, then test the behavior with the HTTP request factory your application actually uses.
This example uses Spring Boot 4.1.2 and Java 17 or later. A shipment-status endpoint normally responds immediately. The same endpoint can delay its response, allowing an integration test to prove which client setting stops the wait.
1. Understand the Two Waits
An HTTP request reaches several stages. The connect timeout applies while the client opens the network connection. Once connected, the client sends the request and waits for response data; the read timeout applies to that wait. In a client that uses a connection pool, acquiring a free pooled connection can introduce a separate wait before either of these stages.
| Stage | What is waiting? | Relevant limit |
|---|---|---|
| Pool acquisition, if a pool is used | A free connection from the pool | Pool or connection-request timeout |
| Connection | A connection to the remote host | Connect timeout |
| Response read | Data from the connected server | Read timeout |
These are client-side time limits. If a timeout expires, the server has not sent an HTTP 408 response to this client; the client gets an I/O error. The exact exception cause and interpretation can depend on the underlying request factory, which is why the example chooses one explicitly.
2. Add the Spring Boot Dependencies
The Web MVC starter supplies a local HTTP endpoint for the test. The REST client starter supplies Spring Boot’s RestTemplateBuilder. The test starter runs the application on a random port and sends a real HTTP request to it.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.2</version>
<relativePath/>
</parent>
<properties><java.version>17</java.version></properties>
<dependencies>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webmvc</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-restclient</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webmvc-test</artifactId><scope>test</scope></dependency>
</dependencies>
Spring Boot manages the starter versions through its parent POM. The complete pom.xml is in the source directory linked at the end of the article.
3. Configure the RestTemplate Timeouts
RestTemplateBuilder accepts Duration values for connectTimeout() and readTimeout(). The client below allows two seconds to connect and one second to wait for response data. It uses SimpleClientHttpRequestFactory explicitly so the test exercises one known implementation instead of whichever request factory the classpath happens to select.
public class ShipmentClient {
private final RestTemplate restTemplate;
public ShipmentClient(RestTemplateBuilder builder) {
this.restTemplate = builder
.requestFactory(SimpleClientHttpRequestFactory.class)
.connectTimeout(Duration.ofSeconds(2))
.readTimeout(Duration.ofSeconds(1))
.build();
}
public ShipmentController.ShipmentStatus status(String baseUrl, long delayMs) {
return restTemplate.getForObject(baseUrl + "/shipments/status?delayMs={delayMs}",
ShipmentController.ShipmentStatus.class, delayMs);
}
}
The two durations configure the factory used by this RestTemplate. They are not a single overall deadline for a request that includes multiple stages. Spring Boot 4.1.2 documents both builder timeout methods; older examples using setConnectTimeout() or setReadTimeout() do not show the current builder API.
In an application, create this client for the remote service you call and inject it where needed. A different service may need different time limits. Spring Boot supplies the builder but does not create a universal shared RestTemplate bean; its REST client guide describes how to customize one.
4. Call a Normal and a Delayed Endpoint
The endpoint models a shipment lookup. With no delay, it returns a status record. For the timeout test, the delayMs query parameter makes the server wait before it writes the same response. This changes only response timing; the URL and returned data stay the same.
@RestController
public class ShipmentController {
@GetMapping("/shipments/status")
public ShipmentStatus status(@RequestParam(defaultValue = "0") long delayMs)
throws InterruptedException {
if (delayMs > 0) {
Thread.sleep(delayMs);
}
return new ShipmentStatus("S-104", "READY_FOR_PICKUP");
}
public record ShipmentStatus(String id, String status) {}
}
The sleep belongs only to this local test endpoint. A production service would do its normal work; its client cannot assume that work will finish within one second. We use a three-second delay to make the response arrive after the client’s one-second read limit without depending on an external service.
5. Verify the Read Timeout
The integration test starts the server on a random port. The immediate request succeeds and returns the expected status. The delayed request throws ResourceAccessException, whose most specific cause is SocketTimeoutException with the chosen simple request factory.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ShipmentClientTest {
@LocalServerPort int port;
@Autowired RestTemplateBuilder builder;
@Test
void immediateResponseSucceeds() {
var client = new ShipmentClient(builder);
var status = client.status("http://localhost:" + port, 0);
assertEquals("READY_FOR_PICKUP", status.status());
}
@Test
void delayedResponseExceedsReadTimeout() {
var client = new ShipmentClient(builder);
var error = assertThrows(ResourceAccessException.class,
() -> client.status("http://localhost:" + port, 3000));
assertInstanceOf(SocketTimeoutException.class, error.getMostSpecificCause());
}
}
Run the tests from the source directory:
mvn test
Both tests passed in the companion project. The delayed call established a local connection before the server waited, so this proves the read timeout, not the connect timeout. We do not assert a precise elapsed time: test startup and scheduling can add time outside the wait being configured.
6. Understand the Limits of This Configuration
The connect timeout matters when the client cannot establish a connection promptly. A server that accepts a connection and then delays its response has already passed that stage, so increasing or decreasing connectTimeout() would not fix the delayed-response example. If your application uses an Apache HttpClient connection pool, waiting for a free pooled connection has a separate timeout controlled by that client configuration. A two-setting builder example does not configure the pool wait.
Likewise, the two settings do not promise one maximum elapsed time for every request. A name lookup, connection, redirects, pool wait and response reads can each affect total duration, depending on the request factory and network conditions. Choose time limits from the service’s expected latency and your caller’s own deadline, then test with the same factory and dependencies used in the application. For a wider discussion of RestTemplate calls, see our RestTemplate overview.
7. Frequently Asked Questions
7.1. Is a read timeout the same as an HTTP 408 response?
No. A read timeout is detected by the client while waiting for data. In this example RestTemplate throws ResourceAccessException. An HTTP 408 is a status line sent by a server or intermediary and has a different origin.
7.2. Why did another request factory produce a different timeout cause?
RestTemplate delegates network I/O to a ClientHttpRequestFactory. In a preliminary run of this example, JdkClientHttpRequestFactory surfaced HttpTimeoutException; the explicit SimpleClientHttpRequestFactory used here surfaced SocketTimeoutException for the delayed read. Avoid catching one low-level cause without first checking the factory used by your application.
7.3. Do connect and read timeouts cap the whole call at three seconds?
No. The two values apply to different waits and do not add up to a guaranteed total deadline. A pooled client can also wait to acquire a connection. If the caller needs an overall deadline, define and enforce that requirement at the appropriate application boundary rather than adding these two numbers.
8. Conclusion
Configure both timeouts on the RestTemplate that calls a remote service and test with its real request factory. A delayed server verifies the read limit; it does not prove the connect limit or a total request deadline.
Happy Learning!
Hi, can you please help me with the exception I am facing in my Spring Boot Application when trying to connect to external service and waiting for the response. The following exception is thrown after 15 minutes from the time the request is hit to the external service.
“Operation timed out (Read failed); nested exception is java.net.SocketException: Operation timed out (Read failed)”
Can setting ReadTimeOut to my RestTemplateBuilder solves the issue?
Hi Lokesh, In my application, I have set timeout limit as 200ms for one API call but in rare scenarios I dont get response in 200ms. So, if I increase the timeout limit to 400ms is it going to impact my application overall response in any way?
No. It will not impact the application performance/timeout on any normal day.
While making delete request, SocketExcption -Unexpected end of file from server is coming while hitting from Web UI app without any delay. If we delay of 2-3 secs then it works fine. Only issue is coming with delete request. We are using Spring boot, Rest template.