diff --git a/python/pydantic_core/core_schema.py b/python/pydantic_core/core_schema.py
index 6644c7fc8..14912f48c 100644
--- a/python/pydantic_core/core_schema.py
+++ b/python/pydantic_core/core_schema.py
@@ -1399,6 +1399,7 @@ class ListSchema(TypedDict, total=False):
     items_schema: CoreSchema
     min_length: int
     max_length: int
+    fail_fast: bool
     strict: bool
     ref: str
     metadata: Any
@@ -1410,6 +1411,7 @@ def list_schema(
     *,
     min_length: int | None = None,
     max_length: int | None = None,
+    fail_fast: bool | None = None,
     strict: bool | None = None,
     ref: str | None = None,
     metadata: Any = None,
@@ -1430,6 +1432,7 @@ def list_schema(
         items_schema: The value must be a list of items that match this schema
         min_length: The value must be a list with at least this many items
         max_length: The value must be a list with at most this many items
+        fail_fast: Stop validation on the first error
         strict: The value must be a list with exactly this many items
         ref: optional unique identifier of the schema, used to reference the schema in other places
         metadata: Any other information you want to include with the schema, not used by pydantic-core
@@ -1440,6 +1443,7 @@ def list_schema(
         items_schema=items_schema,
         min_length=min_length,
         max_length=max_length,
+        fail_fast=fail_fast,
         strict=strict,
         ref=ref,
         metadata=metadata,
@@ -1547,6 +1551,7 @@ class TupleSchema(TypedDict, total=False):
     variadic_item_index: int
     min_length: int
     max_length: int
+    fail_fast: bool
     strict: bool
     ref: str
     metadata: Any
@@ -1559,6 +1564,7 @@ def tuple_schema(
     variadic_item_index: int | None = None,
     min_length: int | None = None,
     max_length: int | None = None,
+    fail_fast: bool | None = None,
     strict: bool | None = None,
     ref: str | None = None,
     metadata: Any = None,
@@ -1583,6 +1589,7 @@ def tuple_schema(
         variadic_item_index: The index of the schema in `items_schema` to be treated as variadic (following PEP 646)
         min_length: The value must be a tuple with at least this many items
         max_length: The value must be a tuple with at most this many items
+        fail_fast: Stop validation on the first error
         strict: The value must be a tuple with exactly this many items
         ref: Optional unique identifier of the schema, used to reference the schema in other places
         metadata: Any other information you want to include with the schema, not used by pydantic-core
@@ -1594,6 +1601,7 @@ def tuple_schema(
         variadic_item_index=variadic_item_index,
         min_length=min_length,
         max_length=max_length,
+        fail_fast=fail_fast,
         strict=strict,
         ref=ref,
         metadata=metadata,
@@ -1606,6 +1614,7 @@ class SetSchema(TypedDict, total=False):
     items_schema: CoreSchema
     min_length: int
     max_length: int
+    fail_fast: bool
     strict: bool
     ref: str
     metadata: Any
@@ -1617,6 +1626,7 @@ def set_schema(
     *,
     min_length: int | None = None,
     max_length: int | None = None,
+    fail_fast: bool | None = None,
     strict: bool | None = None,
     ref: str | None = None,
     metadata: Any = None,
@@ -1639,6 +1649,7 @@ def set_schema(
         items_schema: The value must be a set with items that match this schema
         min_length: The value must be a set with at least this many items
         max_length: The value must be a set with at most this many items
+        fail_fast: Stop validation on the first error
         strict: The value must be a set with exactly this many items
         ref: optional unique identifier of the schema, used to reference the schema in other places
         metadata: Any other information you want to include with the schema, not used by pydantic-core
@@ -1649,6 +1660,7 @@ def set_schema(
         items_schema=items_schema,
         min_length=min_length,
         max_length=max_length,
+        fail_fast=fail_fast,
         strict=strict,
         ref=ref,
         metadata=metadata,
@@ -1661,6 +1673,7 @@ class FrozenSetSchema(TypedDict, total=False):
     items_schema: CoreSchema
     min_length: int
     max_length: int
+    fail_fast: bool
     strict: bool
     ref: str
     metadata: Any
@@ -1672,6 +1685,7 @@ def frozenset_schema(
     *,
     min_length: int | None = None,
     max_length: int | None = None,
+    fail_fast: bool | None = None,
     strict: bool | None = None,
     ref: str | None = None,
     metadata: Any = None,
@@ -1694,6 +1708,7 @@ def frozenset_schema(
         items_schema: The value must be a frozenset with items that match this schema
         min_length: The value must be a frozenset with at least this many items
         max_length: The value must be a frozenset with at most this many items
+        fail_fast: Stop validation on the first error
         strict: The value must be a frozenset with exactly this many items
         ref: optional unique identifier of the schema, used to reference the schema in other places
         metadata: Any other information you want to include with the schema, not used by pydantic-core
@@ -1704,6 +1719,7 @@ def frozenset_schema(
         items_schema=items_schema,
         min_length=min_length,
         max_length=max_length,
+        fail_fast=fail_fast,
         strict=strict,
         ref=ref,
         metadata=metadata,
diff --git a/src/input/return_enums.rs b/src/input/return_enums.rs
index 22faaba71..bbd1b6404 100644
--- a/src/input/return_enums.rs
+++ b/src/input/return_enums.rs
@@ -124,6 +124,7 @@ pub(crate) fn validate_iter_to_vec<'py>(
     mut max_length_check: MaxLengthCheck<'_, impl Input<'py> + ?Sized>,
     validator: &CombinedValidator,
     state: &mut ValidationState<'_, 'py>,
+    fail_fast: bool,
 ) -> ValResult<Vec<PyObject>> {
     let mut output: Vec<PyObject> = Vec::with_capacity(capacity);
     let mut errors: Vec<ValLineError> = Vec::new();
@@ -137,6 +138,9 @@ pub(crate) fn validate_iter_to_vec<'py>(
             Err(ValError::LineErrors(line_errors)) => {
                 max_length_check.incr()?;
                 errors.extend(line_errors.into_iter().map(|err| err.with_outer_location(index)));
+                if fail_fast {
+                    break;
+                }
             }
             Err(ValError::Omit) => (),
             Err(err) => return Err(err),
@@ -190,6 +194,7 @@ pub(crate) fn validate_iter_to_set<'py>(
     max_length: Option<usize>,
     validator: &CombinedValidator,
     state: &mut ValidationState<'_, 'py>,
+    fail_fast: bool,
 ) -> ValResult<()> {
     let mut errors: Vec<ValLineError> = Vec::new();
     for (index, item_result) in iter.enumerate() {
@@ -220,6 +225,9 @@ pub(crate) fn validate_iter_to_set<'py>(
             Err(ValError::Omit) => (),
             Err(err) => return Err(err),
         }
+        if fail_fast && !errors.is_empty() {
+            break;
+        }
     }
 
     if errors.is_empty() {
diff --git a/src/validators/frozenset.rs b/src/validators/frozenset.rs
index fcb7ffe7c..60fe451a7 100644
--- a/src/validators/frozenset.rs
+++ b/src/validators/frozenset.rs
@@ -17,6 +17,7 @@ pub struct FrozenSetValidator {
     min_length: Option<usize>,
     max_length: Option<usize>,
     name: String,
+    fail_fast: bool,
 }
 
 impl BuildValidator for FrozenSetValidator {
@@ -42,6 +43,7 @@ impl Validator for FrozenSetValidator {
             max_length: self.max_length,
             item_validator: &self.item_validator,
             state,
+            fail_fast: self.fail_fast,
         })??;
         min_length_check!(input, "Frozenset", self.min_length, f_set);
         Ok(f_set.into_py(py))
@@ -59,6 +61,7 @@ struct ValidateToFrozenSet<'a, 's, 'py, I: Input<'py> + ?Sized> {
     max_length: Option<usize>,
     item_validator: &'a CombinedValidator,
     state: &'a mut ValidationState<'s, 'py>,
+    fail_fast: bool,
 }
 
 impl<'py, T, I> ConsumeIterator<PyResult<T>> for ValidateToFrozenSet<'_, '_, 'py, I>
@@ -77,6 +80,7 @@ where
             self.max_length,
             self.item_validator,
             self.state,
+            self.fail_fast,
         )
     }
 }
diff --git a/src/validators/list.rs b/src/validators/list.rs
index 21825ca54..87600fb81 100644
--- a/src/validators/list.rs
+++ b/src/validators/list.rs
@@ -18,6 +18,7 @@ pub struct ListValidator {
     min_length: Option<usize>,
     max_length: Option<usize>,
     name: OnceLock<String>,
+    fail_fast: bool,
 }
 
 pub fn get_items_schema(
@@ -109,6 +110,7 @@ impl BuildValidator for ListValidator {
             min_length: schema.get_as(pyo3::intern!(py, "min_length"))?,
             max_length: schema.get_as(pyo3::intern!(py, "max_length"))?,
             name: OnceLock::new(),
+            fail_fast: schema.get_as(pyo3::intern!(py, "fail_fast"))?.unwrap_or(false),
         }
         .into())
     }
@@ -135,6 +137,7 @@ impl Validator for ListValidator {
                 field_type: "List",
                 item_validator: v,
                 state,
+                fail_fast: self.fail_fast,
             })??,
             None => {
                 if let Some(py_list) = seq.as_py_list() {
@@ -184,6 +187,7 @@ struct ValidateToVec<'a, 's, 'py, I: Input<'py> + ?Sized> {
     field_type: &'static str,
     item_validator: &'a CombinedValidator,
     state: &'a mut ValidationState<'s, 'py>,
+    fail_fast: bool,
 }
 
 // pretty arbitrary default capacity when creating vecs from iteration
@@ -204,6 +208,7 @@ where
             max_length_check,
             self.item_validator,
             self.state,
+            self.fail_fast,
         )
     }
 }
diff --git a/src/validators/set.rs b/src/validators/set.rs
index 3ebd2e40b..281cfc37d 100644
--- a/src/validators/set.rs
+++ b/src/validators/set.rs
@@ -15,6 +15,7 @@ pub struct SetValidator {
     min_length: Option<usize>,
     max_length: Option<usize>,
     name: String,
+    fail_fast: bool,
 }
 
 macro_rules! set_build {
@@ -42,6 +43,7 @@ macro_rules! set_build {
                 min_length: schema.get_as(pyo3::intern!(py, "min_length"))?,
                 max_length,
                 name,
+                fail_fast: schema.get_as(pyo3::intern!(py, "fail_fast"))?.unwrap_or(false),
             }
             .into())
         }
@@ -72,6 +74,7 @@ impl Validator for SetValidator {
             max_length: self.max_length,
             item_validator: &self.item_validator,
             state,
+            fail_fast: self.fail_fast,
         })??;
         min_length_check!(input, "Set", self.min_length, set);
         Ok(set.into_py(py))
@@ -89,6 +92,7 @@ struct ValidateToSet<'a, 's, 'py, I: Input<'py> + ?Sized> {
     max_length: Option<usize>,
     item_validator: &'a CombinedValidator,
     state: &'a mut ValidationState<'s, 'py>,
+    fail_fast: bool,
 }
 
 impl<'py, T, I> ConsumeIterator<PyResult<T>> for ValidateToSet<'_, '_, 'py, I>
@@ -107,6 +111,7 @@ where
             self.max_length,
             self.item_validator,
             self.state,
+            self.fail_fast,
         )
     }
 }
diff --git a/src/validators/tuple.rs b/src/validators/tuple.rs
index 3c5adb186..8acbf2beb 100644
--- a/src/validators/tuple.rs
+++ b/src/validators/tuple.rs
@@ -19,6 +19,7 @@ pub struct TupleValidator {
     min_length: Option<usize>,
     max_length: Option<usize>,
     name: String,
+    fail_fast: bool,
 }
 
 impl BuildValidator for TupleValidator {
@@ -50,6 +51,7 @@ impl BuildValidator for TupleValidator {
             min_length: schema.get_as(intern!(py, "min_length"))?,
             max_length: schema.get_as(intern!(py, "max_length"))?,
             name,
+            fail_fast: schema.get_as(intern!(py, "fail_fast"))?.unwrap_or(false),
         }
         .into())
     }
@@ -69,6 +71,7 @@ impl TupleValidator {
         item_validators: &[CombinedValidator],
         collection_iter: &mut NextCountingIterator<impl Iterator<Item = I>>,
         actual_length: Option<usize>,
+        fail_fast: bool,
     ) -> ValResult<()> {
         // Validate the head:
         for validator in item_validators {
@@ -90,6 +93,9 @@ impl TupleValidator {
                     }
                 }
             }
+            if fail_fast && !errors.is_empty() {
+                return Ok(());
+            }
         }
 
         Ok(())
@@ -128,8 +134,13 @@ impl TupleValidator {
                 head_validators,
                 collection_iter,
                 actual_length,
+                self.fail_fast,
             )?;
 
+            if self.fail_fast && !errors.is_empty() {
+                return Ok(output);
+            }
+
             let n_tail_validators = tail_validators.len();
             if n_tail_validators == 0 {
                 for (index, input_item) in collection_iter {
@@ -141,6 +152,10 @@ impl TupleValidator {
                         Err(ValError::Omit) => (),
                         Err(err) => return Err(err),
                     }
+
+                    if self.fail_fast && !errors.is_empty() {
+                        return Ok(output);
+                    }
                 }
             } else {
                 // Populate a buffer with the first n_tail_validators items
@@ -172,6 +187,10 @@ impl TupleValidator {
                         Err(ValError::Omit) => (),
                         Err(err) => return Err(err),
                     }
+
+                    if self.fail_fast && !errors.is_empty() {
+                        return Ok(output);
+                    }
                 }
 
                 // Validate the buffered items using the tail validators
@@ -184,6 +203,7 @@ impl TupleValidator {
                     tail_validators,
                     &mut NextCountingIterator::new(tail_buffer.into_iter(), index),
                     actual_length,
+                    self.fail_fast,
                 )?;
             }
         } else {
@@ -197,8 +217,13 @@ impl TupleValidator {
                 &self.validators,
                 collection_iter,
                 actual_length,
+                self.fail_fast,
             )?;
 
+            if self.fail_fast && !errors.is_empty() {
+                return Ok(output);
+            }
+
             // Generate an error if there are any extra items:
             if collection_iter.next().is_some() {
                 return Err(ValError::new(
diff --git a/tests/validators/test_frozenset.py b/tests/validators/test_frozenset.py
index 407e0a579..e8ddbfc3b 100644
--- a/tests/validators/test_frozenset.py
+++ b/tests/validators/test_frozenset.py
@@ -248,7 +248,8 @@ def test_repr():
         'title="frozenset[any]",'
         'validator=FrozenSet(FrozenSetValidator{'
         'strict:true,item_validator:Any(AnyValidator),min_length:Some(42),max_length:None,'
-        'name:"frozenset[any]"'
+        'name:"frozenset[any]",'
+        'fail_fast:false'
         '}),'
         'definitions=[],'
         'cache_strings=True)'
@@ -296,3 +297,47 @@ def test_frozenset_from_dict_items(input_value, items_schema, expected):
     output = v.validate_python(input_value)
     assert isinstance(output, frozenset)
     assert output == expected
+
+
+@pytest.mark.parametrize(
+    'fail_fast,expected',
+    [
+        pytest.param(
+            True,
+            [
+                {
+                    'type': 'int_parsing',
+                    'loc': (1,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'not-num',
+                },
+            ],
+            id='fail_fast',
+        ),
+        pytest.param(
+            False,
+            [
+                {
+                    'type': 'int_parsing',
+                    'loc': (1,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'not-num',
+                },
+                {
+                    'type': 'int_parsing',
+                    'loc': (2,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'again',
+                },
+            ],
+            id='not_fail_fast',
+        ),
+    ],
+)
+def test_frozenset_fail_fast(fail_fast, expected):
+    v = SchemaValidator({'type': 'frozenset', 'items_schema': {'type': 'int'}, 'fail_fast': fail_fast})
+
+    with pytest.raises(ValidationError) as exc_info:
+        v.validate_python([1, 'not-num', 'again'])
+
+    assert exc_info.value.errors(include_url=False) == expected
diff --git a/tests/validators/test_list.py b/tests/validators/test_list.py
index 9f7d8738f..b8bcee8ec 100644
--- a/tests/validators/test_list.py
+++ b/tests/validators/test_list.py
@@ -397,6 +397,51 @@ def f(v: int) -> int:
     )
 
 
+@pytest.mark.parametrize(
+    'fail_fast,expected',
+    [
+        pytest.param(
+            True,
+            [
+                {
+                    'type': 'int_parsing',
+                    'loc': (1,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'not-num',
+                }
+            ],
+            id='fail_fast',
+        ),
+        pytest.param(
+            False,
+            [
+                {
+                    'type': 'int_parsing',
+                    'loc': (1,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'not-num',
+                },
+                {
+                    'type': 'int_parsing',
+                    'loc': (2,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'again',
+                },
+            ],
+            id='not_fail_fast',
+        ),
+    ],
+)
+def test_list_fail_fast(fail_fast, expected):
+    s = core_schema.list_schema(core_schema.int_schema(), fail_fast=fail_fast)
+    v = SchemaValidator(s)
+
+    with pytest.raises(ValidationError) as exc_info:
+        v.validate_python([1, 'not-num', 'again'])
+
+    assert exc_info.value.errors(include_url=False) == expected
+
+
 class MySequence(collections.abc.Sequence):
     def __init__(self, data: List[Any]):
         self._data = data
diff --git a/tests/validators/test_set.py b/tests/validators/test_set.py
index e58cedff8..3c044658c 100644
--- a/tests/validators/test_set.py
+++ b/tests/validators/test_set.py
@@ -277,3 +277,47 @@ def test_set_any(input_value, expected):
     output = v.validate_python(input_value)
     assert output == expected
     assert isinstance(output, set)
+
+
+@pytest.mark.parametrize(
+    'fail_fast,expected',
+    [
+        pytest.param(
+            True,
+            [
+                {
+                    'type': 'int_parsing',
+                    'loc': (1,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'not-num',
+                },
+            ],
+            id='fail_fast',
+        ),
+        pytest.param(
+            False,
+            [
+                {
+                    'type': 'int_parsing',
+                    'loc': (1,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'not-num',
+                },
+                {
+                    'type': 'int_parsing',
+                    'loc': (2,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'again',
+                },
+            ],
+            id='not_fail_fast',
+        ),
+    ],
+)
+def test_set_fail_fast(fail_fast, expected):
+    v = SchemaValidator({'type': 'set', 'items_schema': {'type': 'int'}, 'fail_fast': fail_fast})
+
+    with pytest.raises(ValidationError) as exc_info:
+        v.validate_python([1, 'not-num', 'again'])
+
+    assert exc_info.value.errors(include_url=False) == expected
diff --git a/tests/validators/test_tuple.py b/tests/validators/test_tuple.py
index a3d548ced..d25ef9547 100644
--- a/tests/validators/test_tuple.py
+++ b/tests/validators/test_tuple.py
@@ -58,8 +58,9 @@ def test_tuple_strict_passes_with_tuple(variadic_item_index, items, input_value,
     assert v.validate_python(input_value) == expected
 
 
-def test_empty_positional_tuple():
-    v = SchemaValidator({'type': 'tuple', 'items_schema': []})
+@pytest.mark.parametrize('fail_fast', [True, False])
+def test_empty_positional_tuple(fail_fast):
+    v = SchemaValidator({'type': 'tuple', 'items_schema': [], 'fail_fast': fail_fast})
     assert v.validate_python(()) == ()
     assert v.validate_python([]) == ()
     with pytest.raises(ValidationError) as exc_info:
@@ -493,3 +494,56 @@ def test_length_constraints_omit(input_value, expected):
             v.validate_python(input_value)
     else:
         assert v.validate_python(input_value) == expected
+
+
+@pytest.mark.parametrize(
+    'fail_fast,expected',
+    [
+        pytest.param(
+            True,
+            [
+                {
+                    'type': 'int_parsing',
+                    'loc': (1,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'not-num',
+                }
+            ],
+            id='fail_fast',
+        ),
+        pytest.param(
+            False,
+            [
+                {
+                    'type': 'int_parsing',
+                    'loc': (1,),
+                    'msg': 'Input should be a valid integer, unable to parse string as an integer',
+                    'input': 'not-num',
+                },
+                {
+                    'type': 'float_parsing',
+                    'loc': (2,),
+                    'msg': 'Input should be a valid number, unable to parse string as a number',
+                    'input': 'again',
+                },
+            ],
+            id='not_fail_fast',
+        ),
+    ],
+)
+def test_tuple_fail_fast(fail_fast, expected):
+    s = core_schema.tuple_schema(
+        [
+            core_schema.str_schema(),
+            core_schema.int_schema(),
+            core_schema.float_schema(),
+        ],
+        variadic_item_index=None,
+        fail_fast=fail_fast,
+    )
+    v = SchemaValidator(s)
+
+    with pytest.raises(ValidationError) as exc_info:
+        v.validate_python(['str', 'not-num', 'again'])
+
+    assert exc_info.value.errors(include_url=False) == expected