diff --git a/.cirrus.yml b/.cirrus.yml
index e3f777b52907f3f44bfa35cc3b5697b4c0669955..4fb29f518069b66df7dd859d658b453df45e1538 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -1,3 +1,17 @@
+task:
+  name: nightly x86_64-unknown-freebsd-10
+  freebsd_instance:
+    image: freebsd-10-4-release-amd64 
+  setup_script:
+    - pkg install -y curl
+    - curl https://sh.rustup.rs -sSf --output rustup.sh
+    - sh rustup.sh --default-toolchain nightly -y
+    - . $HOME/.cargo/env
+    - rustup default nightly
+  test_script:
+    - . $HOME/.cargo/env
+    - LIBC_CI=1 sh ci/run.sh x86_64-unknown-freebsd
+ 
 task:
   name: stable x86_64-unknown-freebsd-11
   freebsd_instance:
diff --git a/build.rs b/build.rs
index d9d23ca2ac9a88b9777a38a1c29487873e6b64f3..d5bcb5253a4c88453c701ce355fd36fb38cd0e9e 100644
--- a/build.rs
+++ b/build.rs
@@ -16,11 +16,15 @@ fn main() {
         );
     }
 
-    // The ABI of libc is backward compatible with FreeBSD 11.
+    // The ABI of libc used by libstd is backward compatible with FreeBSD 10.
+    // The ABI of libc from crates.io is backward compatible with FreeBSD 11.
     //
     // On CI, we detect the actual FreeBSD version and match its ABI exactly,
     // running tests to ensure that the ABI is correct.
     match which_freebsd() {
+        Some(10) if libc_ci || rustc_dep_of_std => {
+            println!("cargo:rustc-cfg=freebsd10")
+        }
         Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"),
         Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"),
         Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"),
@@ -109,6 +113,7 @@ fn which_freebsd() -> Option<i32> {
     let stdout = stdout.unwrap();
 
     match &stdout {
+        s if s.starts_with("10") => Some(10),
         s if s.starts_with("11") => Some(11),
         s if s.starts_with("12") => Some(12),
         s if s.starts_with("13") => Some(13),
diff --git a/libc-test/build.rs b/libc-test/build.rs
index 861fc21b093f2b434556e064d49c6dbbcf867d6d..73ac02decb85f7ba8153765c46a5e39298245343 100644
--- a/libc-test/build.rs
+++ b/libc-test/build.rs
@@ -1457,6 +1457,7 @@ fn test_freebsd(target: &str) {
     let freebsd_ver = which_freebsd();
 
     match freebsd_ver {
+        Some(10) => cfg.cfg("freebsd10", None),
         Some(11) => cfg.cfg("freebsd11", None),
         Some(12) => cfg.cfg("freebsd12", None),
         Some(13) => cfg.cfg("freebsd13", None),
@@ -1466,7 +1467,10 @@ fn test_freebsd(target: &str) {
     // Required for `getline`:
     cfg.define("_WITH_GETLINE", None);
     // Required for making freebsd11_stat available in the headers
-    cfg.define("_WANT_FREEBSD11_STAT", None);
+    match freebsd_ver {
+        Some(10) => &mut cfg,
+        _ => cfg.define("_WANT_FREEBSD11_STAT", None),
+    };
 
     headers! { cfg:
                 "aio.h",
@@ -1594,6 +1598,34 @@ fn test_freebsd(target: &str) {
                 true
             }
 
+            // These constants were introduced in FreeBSD 11:
+            "SF_USER_READAHEAD"
+            | "SF_NOCACHE"
+            | "RLIMIT_KQUEUES"
+            | "RLIMIT_UMTXP"
+            | "EVFILT_PROCDESC"
+            | "EVFILT_SENDFILE"
+            | "EVFILT_EMPTY"
+            | "SO_REUSEPORT_LB"
+            | "TCP_CCALGOOPT"
+            | "TCP_PCAP_OUT"
+            | "TCP_PCAP_IN"
+            | "IP_BINDMULTI"
+            | "IP_ORIGDSTADDR"
+            | "IP_RECVORIGDSTADDR"
+            | "IPV6_ORIGDSTADDR"
+            | "IPV6_RECVORIGDSTADDR"
+            | "PD_CLOEXEC"
+            | "PD_ALLOWED_AT_FORK"
+            | "IP_RSS_LISTEN_BUCKET"
+                if Some(10) == freebsd_ver =>
+            {
+                true
+            }
+
+            // FIXME: This constant has a different value in FreeBSD 10:
+            "RLIM_NLIMITS" if Some(10) == freebsd_ver => true,
+
             // FIXME: There are deprecated - remove in a couple of releases.
             // These constants were removed in FreeBSD 11 (svn r273250) but will
             // still be accepted and ignored at runtime.
@@ -1609,12 +1641,32 @@ fn test_freebsd(target: &str) {
         }
     });
 
+    cfg.skip_struct(move |ty| {
+        match ty {
+            // `mmsghdr` is not available in FreeBSD 10
+            "mmsghdr" if Some(10) == freebsd_ver => true,
+
+            _ => false,
+        }
+    });
+
     cfg.skip_fn(move |name| {
         // skip those that are manually verified
         match name {
             // FIXME: https://github.com/rust-lang/libc/issues/1272
             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
 
+            // These functions were added in FreeBSD 11:
+            "fdatasync" | "mq_getfd_np" | "sendmmsg" | "recvmmsg"
+                if Some(10) == freebsd_ver =>
+            {
+                true
+            }
+
+            // This function changed its return type from `int` in FreeBSD10 to
+            // `ssize_t` in FreeBSD11:
+            "aio_waitcomplete" if Some(10) == freebsd_ver => true,
+
             // The `uname` function in the `utsname.h` FreeBSD header is a C
             // inline function (has no symbol) that calls the `__xuname` symbol.
             // Therefore the function pointer comparison does not make sense for it.
@@ -1630,6 +1682,14 @@ fn test_freebsd(target: &str) {
         }
     });
 
+    cfg.skip_signededness(move |c| {
+        match c {
+            // FIXME: has a different sign in FreeBSD10
+            "blksize_t" if Some(10) == freebsd_ver => true,
+            _ => false,
+        }
+    });
+
     cfg.volatile_item(|i| {
         use ctest::VolatileItemKind::*;
         match i {
@@ -1643,9 +1703,17 @@ fn test_freebsd(target: &str) {
     });
 
     cfg.skip_field(move |struct_, field| {
-        // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
-        // incorrect, see: https://github.com/rust-lang/libc/issues/1359
-        (struct_ == "sigaction" && field == "sa_sigaction")
+        match (struct_, field) {
+            // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
+            // incorrect, see: https://github.com/rust-lang/libc/issues/1359
+            ("sigaction", "sa_sigaction") => true,
+
+            // FIXME: in FreeBSD10 this field has type `char*` instead of
+            // `void*`:
+            ("stack_t", "ss_sp") if Some(10) == freebsd_ver => true,
+
+            _ => false,
+        }
     });
 
     cfg.generate("../src/lib.rs", "main.rs");
@@ -2457,6 +2525,7 @@ fn which_freebsd() -> Option<i32> {
     let stdout = String::from_utf8(output.stdout).ok()?;
 
     match &stdout {
+        s if s.starts_with("10") => Some(10),
         s if s.starts_with("11") => Some(11),
         s if s.starts_with("12") => Some(12),
         s if s.starts_with("13") => Some(13),
diff --git a/src/unix/bsd/freebsdlike/freebsd/mod.rs b/src/unix/bsd/freebsdlike/freebsd/mod.rs
index 9acc3fcc33fac998eb49bef5c45e588328d2fa5d..980caf225765d609440a313c17aa58047c94c882 100644
--- a/src/unix/bsd/freebsdlike/freebsd/mod.rs
+++ b/src/unix/bsd/freebsdlike/freebsd/mod.rs
@@ -1456,7 +1456,7 @@ cfg_if! {
     } else if #[cfg(freebsd13)] {
         mod freebsd12;
         pub use self::freebsd12::*;
-    } else if #[cfg(freebsd11)] {
+    } else if #[cfg(any(freebsd10, freebsd11))] {
         mod freebsd11;
         pub use self::freebsd11::*;
     } else {
diff --git a/src/unix/bsd/freebsdlike/mod.rs b/src/unix/bsd/freebsdlike/mod.rs
index c1128952f2a64c238fb4e8ef912f1af6f8556ccc..9ddb6014d39e9bb500719989c7deae49ff885c2b 100644
--- a/src/unix/bsd/freebsdlike/mod.rs
+++ b/src/unix/bsd/freebsdlike/mod.rs
@@ -1193,7 +1193,7 @@ extern "C" {
     pub fn getutxline(ut: *const utmpx) -> *mut utmpx;
     pub fn initgroups(name: *const ::c_char, basegid: ::gid_t) -> ::c_int;
     #[cfg_attr(
-        all(target_os = "freebsd", freebsd11),
+        all(target_os = "freebsd", any(freebsd11, freebsd10)),
         link_name = "kevent@FBSD_1.0"
     )]
     pub fn kevent(
@@ -1223,7 +1223,7 @@ extern "C" {
         mode: ::mode_t,
     ) -> ::c_int;
     #[cfg_attr(
-        all(target_os = "freebsd", freebsd11),
+        all(target_os = "freebsd", any(freebsd11, freebsd10)),
         link_name = "mknodat@FBSD_1.1"
     )]
     pub fn mknodat(
diff --git a/src/unix/bsd/mod.rs b/src/unix/bsd/mod.rs
index 6cb40a0d804f813dbe34c6b998a1708941a18be7..cf9f59e9b3c025fcc552961cfe60edcc176858ba 100644
--- a/src/unix/bsd/mod.rs
+++ b/src/unix/bsd/mod.rs
@@ -558,7 +558,7 @@ extern "C" {
     #[cfg_attr(target_os = "macos", link_name = "glob$INODE64")]
     #[cfg_attr(target_os = "netbsd", link_name = "__glob30")]
     #[cfg_attr(
-        all(target_os = "freebsd", freebsd11),
+        all(target_os = "freebsd", any(freebsd11, freebsd10)),
         link_name = "glob@FBSD_1.0"
     )]
     pub fn glob(
@@ -571,7 +571,7 @@ extern "C" {
     ) -> ::c_int;
     #[cfg_attr(target_os = "netbsd", link_name = "__globfree30")]
     #[cfg_attr(
-        all(target_os = "freebsd", freebsd11),
+        all(target_os = "freebsd", any(freebsd11, freebsd10)),
         link_name = "globfree@FBSD_1.0"
     )]
     pub fn globfree(pglob: *mut ::glob_t);
diff --git a/src/unix/mod.rs b/src/unix/mod.rs
index 15656de95fd923898608551f51d080d6fbbf5dd1..238da24b51e3d111e8135d2ae108813f01eddf55 100644
--- a/src/unix/mod.rs
+++ b/src/unix/mod.rs
@@ -669,7 +669,7 @@ extern "C" {
     #[cfg_attr(target_os = "macos", link_name = "fstat$INODE64")]
     #[cfg_attr(target_os = "netbsd", link_name = "__fstat50")]
     #[cfg_attr(
-        all(target_os = "freebsd", freebsd11),
+        all(target_os = "freebsd", any(freebsd11, freebsd10)),
         link_name = "fstat@FBSD_1.0"
     )]
     pub fn fstat(fildes: ::c_int, buf: *mut stat) -> ::c_int;
@@ -679,7 +679,7 @@ extern "C" {
     #[cfg_attr(target_os = "macos", link_name = "stat$INODE64")]
     #[cfg_attr(target_os = "netbsd", link_name = "__stat50")]
     #[cfg_attr(
-        all(target_os = "freebsd", freebsd11),
+        all(target_os = "freebsd", any(freebsd11, freebsd10)),
         link_name = "stat@FBSD_1.0"
     )]
     pub fn stat(path: *const c_char, buf: *mut stat) -> ::c_int;
@@ -722,7 +722,7 @@ extern "C" {
     #[cfg_attr(target_os = "macos", link_name = "readdir$INODE64")]
     #[cfg_attr(target_os = "netbsd", link_name = "__readdir30")]
     #[cfg_attr(
-        all(target_os = "freebsd", freebsd11),
+        all(target_os = "freebsd", any(freebsd11, freebsd10)),
         link_name = "readdir@FBSD_1.0"
     )]
     pub fn readdir(dirp: *mut ::DIR) -> *mut ::dirent;
@@ -757,7 +757,7 @@ extern "C" {
     ) -> ::c_int;
     #[cfg_attr(target_os = "macos", link_name = "fstatat$INODE64")]
     #[cfg_attr(
-        all(target_os = "freebsd", freebsd11),
+        all(target_os = "freebsd", any(freebsd11, freebsd10)),
         link_name = "fstatat@FBSD_1.1"
     )]
     pub fn fstatat(
@@ -989,7 +989,7 @@ extern "C" {
     #[cfg_attr(target_os = "macos", link_name = "lstat$INODE64")]
     #[cfg_attr(target_os = "netbsd", link_name = "__lstat50")]
     #[cfg_attr(
-        all(target_os = "freebsd", freebsd11),
+        all(target_os = "freebsd", any(freebsd11, freebsd10)),
         link_name = "lstat@FBSD_1.0"
     )]
     pub fn lstat(path: *const c_char, buf: *mut stat) -> ::c_int;
@@ -1242,7 +1242,7 @@ extern "C" {
 
     #[cfg_attr(target_os = "netbsd", link_name = "__mknod50")]
     #[cfg_attr(
-        all(target_os = "freebsd", freebsd11),
+        all(target_os = "freebsd", any(freebsd11, freebsd10)),
         link_name = "mknod@FBSD_1.0"
     )]
     pub fn mknod(
@@ -1458,7 +1458,7 @@ cfg_if! {
             #[cfg_attr(target_os = "macos", link_name = "readdir_r$INODE64")]
             #[cfg_attr(target_os = "netbsd", link_name = "__readdir_r30")]
             #[cfg_attr(
-                all(target_os = "freebsd", freebsd11),
+                all(target_os = "freebsd", any(freebsd11, freebsd10)),
                 link_name = "readdir_r@FBSD_1.0"
             )]
             /// The 64-bit libc on Solaris and illumos only has readdir_r.  If a