diff --git a/lib/helpers/model/castBulkWrite.js b/lib/helpers/model/castBulkWrite.js
index f566764a2e6..01e3cdd36c4 100644
--- a/lib/helpers/model/castBulkWrite.js
+++ b/lib/helpers/model/castBulkWrite.js
@@ -29,7 +29,7 @@ module.exports = function castBulkWrite(originalModel, op, options) {
       const model = decideModelByObject(originalModel, op['insertOne']['document']);
 
       const doc = new model(op['insertOne']['document']);
-      if (model.schema.options.timestamps && options.timestamps !== false) {
+      if (model.schema.options.timestamps && getTimestampsOpt(op['insertOne'], options)) {
         doc.initializeTimestamps();
       }
       if (options.session != null) {
@@ -69,13 +69,15 @@ module.exports = function castBulkWrite(originalModel, op, options) {
 
         _addDiscriminatorToObject(schema, op['updateOne']['filter']);
 
-        if (model.schema.$timestamps != null && op['updateOne'].timestamps !== false) {
+        const doInitTimestamps = getTimestampsOpt(op['updateOne'], options);
+        
+        if (model.schema.$timestamps != null && doInitTimestamps) {
           const createdAt = model.schema.$timestamps.createdAt;
           const updatedAt = model.schema.$timestamps.updatedAt;
           applyTimestampsToUpdate(now, createdAt, updatedAt, update, {});
         }
 
-        if (op['updateOne'].timestamps !== false) {
+        if (doInitTimestamps) {
           applyTimestampsToChildren(now, update, model.schema);
         }
 
@@ -134,12 +136,14 @@ module.exports = function castBulkWrite(originalModel, op, options) {
           });
         }
 
-        if (model.schema.$timestamps != null && op['updateMany'].timestamps !== false) {
+        const doInitTimestamps = getTimestampsOpt(op['updateMany'], options);
+
+        if (model.schema.$timestamps != null && doInitTimestamps) {
           const createdAt = model.schema.$timestamps.createdAt;
           const updatedAt = model.schema.$timestamps.updatedAt;
           applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateMany']['update'], {});
         }
-        if (op['updateMany'].timestamps !== false) {
+        if (doInitTimestamps) {
           applyTimestampsToChildren(now, op['updateMany']['update'], model.schema);
         }
 
@@ -184,7 +188,7 @@ module.exports = function castBulkWrite(originalModel, op, options) {
 
       // set `skipId`, otherwise we get "_id field cannot be changed"
       const doc = new model(op['replaceOne']['replacement'], strict, true);
-      if (model.schema.options.timestamps) {
+      if (model.schema.options.timestamps && getTimestampsOpt(op['replaceOne'], options)) {
         doc.initializeTimestamps();
       }
       if (options.session != null) {
@@ -273,3 +277,20 @@ function decideModelByObject(model, object) {
   }
   return model;
 }
+
+
+/**
+ * gets timestamps option for a given operation. If the option is set within an individual operation, use it. Otherwise, use the global timestamps option configured in the `bulkWrite` options. Overall default is `true`.
+ * @api private
+ */
+
+function getTimestampsOpt(opCommand, options) {
+  const opLevelOpt = opCommand.timestamps;
+  const bulkLevelOpt = options.timestamps;
+  if (opLevelOpt != null) {
+    return opLevelOpt;
+  } else if (bulkLevelOpt != null) {
+    return bulkLevelOpt;
+  }
+  return true;
+}
diff --git a/lib/model.js b/lib/model.js
index d07fe2b89fb..5e0a105c479 100644
--- a/lib/model.js
+++ b/lib/model.js
@@ -3467,6 +3467,7 @@ function _setIsNew(doc, val) {
  *
  * @param {Array} ops
  * @param {Object} [ops.insertOne.document] The document to insert
+ * @param {Object} [ops.insertOne.timestamps=true] If false, do not apply [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) to the operation
  * @param {Object} [ops.updateOne.filter] Update the first document that matches this filter
  * @param {Object} [ops.updateOne.update] An object containing [update operators](https://www.mongodb.com/docs/manual/reference/operator/update/)
  * @param {Boolean} [ops.updateOne.upsert=false] If true, insert a doc if none match
@@ -3484,8 +3485,10 @@ function _setIsNew(doc, val) {
  * @param {Object} [ops.replaceOne.filter] Replace the first document that matches this filter
  * @param {Object} [ops.replaceOne.replacement] The replacement document
  * @param {Boolean} [ops.replaceOne.upsert=false] If true, insert a doc if no documents match `filter`
+ * @param {Object} [ops.replaceOne.timestamps=true] If false, do not apply [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) to the operation
  * @param {Object} [options]
  * @param {Boolean} [options.ordered=true] If true, execute writes in order and stop at the first error. If false, execute writes in parallel and continue until all writes have either succeeded or errored.
+ * @param {Boolean} [options.timestamps=true] If false, do not apply [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) to any operations. Can be overridden at the operation-level.
  * @param {ClientSession} [options.session=null] The session associated with this bulk write. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
  * @param {String|number} [options.w=1] The [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/). See [`Query#w()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.w()) for more information.
  * @param {number} [options.wtimeout=null] The [write concern timeout](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout).
diff --git a/types/models.d.ts b/types/models.d.ts
index 65893729490..2bbb2663009 100644
--- a/types/models.d.ts
+++ b/types/models.d.ts
@@ -28,6 +28,8 @@ declare module 'mongoose' {
     skipValidation?: boolean;
     throwOnValidationError?: boolean;
     strict?: boolean | 'throw';
+    /** When false, do not add timestamps to documents. Can be overridden at the operation level. */
+    timestamps?: boolean;
   }
 
   interface MongooseBulkSaveOptions extends mongodb.BulkWriteOptions {
@@ -179,7 +181,9 @@ declare module 'mongoose' {
   };
 
   export interface InsertOneModel<TSchema> {
-    document: mongodb.OptionalId<TSchema>
+    document: mongodb.OptionalId<TSchema>;
+    /** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
+    timestamps?: boolean;
   }
 
   export interface ReplaceOneModel<TSchema = AnyObject> {
@@ -193,6 +197,8 @@ declare module 'mongoose' {
     hint?: mongodb.Hint;
     /** When true, creates a new document if no document matches the query. */
     upsert?: boolean;
+    /** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
+    timestamps?: boolean;
   }
 
   export interface UpdateOneModel<TSchema = AnyObject> {
@@ -208,7 +214,7 @@ declare module 'mongoose' {
     hint?: mongodb.Hint;
     /** When true, creates a new document if no document matches the query. */
     upsert?: boolean;
-    /** When false, do not add timestamps. */
+    /** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
     timestamps?: boolean;
   }
 
@@ -225,7 +231,7 @@ declare module 'mongoose' {
     hint?: mongodb.Hint;
     /** When true, creates a new document if no document matches the query. */
     upsert?: boolean;
-    /** When false, do not add timestamps. */
+    /** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
     timestamps?: boolean;
   }