diff --git a/vendor/magento/module-catalog/Block/Product/ListProduct.php b/vendor/magento/module-catalog/Block/Product/ListProduct.php
index 5b8cb6a1919..ab50e83e967 100644
--- a/vendor/magento/module-catalog/Block/Product/ListProduct.php
+++ b/vendor/magento/module-catalog/Block/Product/ListProduct.php
@@ -43,15 +43,11 @@ class ListProduct extends AbstractProduct implements IdentityInterface
     protected $_defaultToolbarBlock = Toolbar::class;
 
     /**
-     * Product Collection
-     *
      * @var AbstractCollection
      */
     protected $_productCollection;
 
     /**
-     * Catalog layer
-     *
      * @var Layer
      */
     protected $_catalogLayer;
@@ -427,8 +423,10 @@ class ListProduct extends AbstractProduct implements IdentityInterface
      */
     protected function getPriceRender()
     {
-        return $this->getLayout()->getBlock('product.price.render.default')
-            ->setData('is_product_list', true);
+        $block = $this->getLayout()->getBlock('product.price.render.default');
+        $block->setData('is_product_list', true);
+
+        return $block->setData('product_list', $this->_productCollection);
     }
 
     /**
diff --git a/vendor/magento/module-configurable-product/Pricing/Price/SpecialPriceBulkResolver.php b/vendor/magento/module-configurable-product/Pricing/Price/SpecialPriceBulkResolver.php
new file mode 100644
index 00000000000..611aa15109f
--- /dev/null
+++ b/vendor/magento/module-configurable-product/Pricing/Price/SpecialPriceBulkResolver.php
@@ -0,0 +1,212 @@
+<?php
+/************************************************************************
+ *
+ * ADOBE CONFIDENTIAL
+ * ___________________
+ *
+ * Copyright 2014 Adobe
+ * All Rights Reserved.
+ *
+ * NOTICE: All information contained herein is, and remains
+ * the property of Adobe and its suppliers, if any. The intellectual
+ * and technical concepts contained herein are proprietary to Adobe
+ * and its suppliers and are protected by all applicable intellectual
+ * property laws, including trade secret and copyright laws.
+ * Dissemination of this information or reproduction of this material
+ * is strictly forbidden unless prior written permission is obtained
+ * from Adobe.
+ * ************************************************************************
+ */
+declare(strict_types=1);
+
+namespace Magento\ConfigurableProduct\Pricing\Price;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Catalog\Model\Category;
+use Magento\Catalog\Model\Product;
+use Magento\Eav\Model\Entity\Collection\AbstractCollection;
+use Magento\Framework\App\ResourceConnection;
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+use Magento\Framework\Cache\FrontendInterface;
+use Magento\Framework\EntityManager\MetadataPool;
+
+class SpecialPriceBulkResolver
+{
+    private const DEFAULT_CACHE_LIFE_TIME = 31536000;
+
+    /**
+     * @var ResourceConnection
+     */
+    private ResourceConnection $resource;
+
+    /**
+     * @var MetadataPool
+     */
+    private MetadataPool $metadataPool;
+
+    /**
+     * @var FrontendInterface
+     */
+    private FrontendInterface $cache;
+
+    /**
+     * @var int
+     */
+    private int $cacheLifeTime;
+
+    /**
+     * @param ResourceConnection $resource
+     * @param MetadataPool $metadataPool
+     * @param FrontendInterface $cache
+     * @param int $cacheLifeTime
+     */
+    public function __construct(
+        ResourceConnection $resource,
+        MetadataPool $metadataPool,
+        FrontendInterface $cache,
+        int $cacheLifeTime = self::DEFAULT_CACHE_LIFE_TIME
+    ) {
+        $this->resource = $resource;
+        $this->metadataPool = $metadataPool;
+        $this->cache = $cache;
+        $this->cacheLifeTime = $cacheLifeTime;
+    }
+
+    /**
+     * Determines if blocks have special prices
+     *
+     * @param int $storeId
+     * @param AbstractCollection|null $productCollection
+     * @return array
+     * @throws \Exception
+     */
+    public function generateSpecialPriceMap(int $storeId, ?AbstractCollection $productCollection): array
+    {
+        if (!$productCollection) {
+            return [];
+        }
+        $cacheKey = $this->getCacheKey($storeId, $productCollection);
+        $cachedData = $this->getCachedData($cacheKey);
+        if ($cachedData === null) {
+            $configurableProducts = $this->filterConfigurableProducts($productCollection);
+            $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
+            $connection = $this->resource->getConnection();
+            $select = $connection->select()
+                ->from(
+                    ['link' => $this->resource->getTableName('catalog_product_super_link')]
+                )
+                ->joinInner(
+                    ['e' => $this->resource->getTableName('catalog_product_entity')],
+                    'link.parent_id = e.' . $metadata->getLinkField()
+                )
+                ->joinInner(
+                    ['product_website' => $this->resource->getTableName('catalog_product_website')],
+                    'product_website.product_id = link.product_id'
+                )
+                ->joinLeft(
+                    ['price' => $this->resource->getTableName('catalog_product_index_price')],
+                    'price.entity_id = link.product_id AND price.website_id = ' . $storeId .
+                    ' AND price.customer_group_id = 0'
+                )
+                ->where('e.entity_id IN (' . implode(',', $configurableProducts) . ')')
+                ->columns(
+                    [
+                        'link.product_id',
+                        '(price.final_price < price.price) AS hasSpecialPrice',
+                        'e.' . $metadata->getLinkField() . ' AS identifier',
+                        'e.entity_id'
+                    ]
+                );
+            $data = $connection->fetchAssoc($select);
+            $map = [];
+            foreach ($data as $specialPriceInfo) {
+                if (!isset($map[$specialPriceInfo['entity_id']])) {
+                    $map[$specialPriceInfo['entity_id']] = (bool) $specialPriceInfo['hasSpecialPrice'];
+                } else {
+                    if ($specialPriceInfo['hasSpecialPrice'] > $map[$specialPriceInfo['entity_id']]) {
+                        $map[$specialPriceInfo['entity_id']] = true;
+                    }
+                }
+
+            }
+            $this->saveCachedData($cacheKey, $map, array_column($data, 'identifier'));
+
+            return $map;
+        }
+
+        return $cachedData;
+    }
+
+    /**
+     * Returns only configurable product ids
+     *
+     * @param AbstractCollection $productCollection
+     * @return array
+     */
+    private function filterConfigurableProducts(AbstractCollection $productCollection): array
+    {
+        $configurableProductIds = [];
+        /** @var Product $product */
+        foreach ($productCollection->getItems() as $product) {
+            if ($product->getTypeId() == Configurable::TYPE_CODE) {
+                $configurableProductIds[] = $product->getEntityId();
+            }
+        }
+
+        return $configurableProductIds;
+    }
+
+    /**
+     * Generate cache key
+     *
+     * @param int $storeId
+     * @param AbstractCollection $productCollection
+     * @return string
+     */
+    private function getCacheKey(int $storeId, AbstractCollection $productCollection): string
+    {
+        $keyParts = $productCollection->getAllIds();
+        $keyParts[] = 'store_id_' . $storeId;
+
+        return hash('sha256', implode('_', $keyParts));
+    }
+
+    /**
+     * Retrieve potential cached data
+     *
+     * @param string $cacheKey
+     * @return array|null
+     */
+    private function getCachedData(string $cacheKey): ?array
+    {
+        $data = $this->cache->load($cacheKey);
+        if (!$data) {
+            return null;
+        }
+
+        return json_decode($data, true);
+    }
+
+    /**
+     * Store data in cache
+     *
+     * @param string $cacheKey
+     * @param array $data
+     * @param array $productTags
+     * @return bool
+     */
+    private function saveCachedData(string $cacheKey, array $data, array $productTags): bool
+    {
+        $tags = [
+            Category::CACHE_TAG,
+            Product::CACHE_TAG,
+            'price'
+        ];
+        $productTags = array_unique($productTags);
+        foreach ($productTags as $tag) {
+            $tags[] = Configurable::TYPE_CODE . '_' . $tag;
+        }
+
+        return $this->cache->save(json_encode($data), $cacheKey, $tags, $this->cacheLifeTime);
+    }
+}
diff --git a/vendor/magento/module-configurable-product/Pricing/Render/FinalPriceBox.php b/vendor/magento/module-configurable-product/Pricing/Render/FinalPriceBox.php
index b48a987c235..3582f1d8176 100644
--- a/vendor/magento/module-configurable-product/Pricing/Render/FinalPriceBox.php
+++ b/vendor/magento/module-configurable-product/Pricing/Render/FinalPriceBox.php
@@ -9,6 +9,7 @@ use Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface;
 use Magento\Catalog\Pricing\Price\FinalPrice;
 use Magento\Catalog\Pricing\Price\MinimalPriceCalculatorInterface;
 use Magento\Catalog\Pricing\Price\RegularPrice;
+use Magento\ConfigurableProduct\Pricing\Price\SpecialPriceBulkResolver;
 use Magento\ConfigurableProduct\Pricing\Price\ConfigurableOptionsProviderInterface;
 use Magento\Framework\Pricing\Price\PriceInterface;
 use Magento\Framework\Pricing\Render\RendererPool;
@@ -23,7 +24,17 @@ class FinalPriceBox extends \Magento\Catalog\Pricing\Render\FinalPriceBox
     /**
      * @var ConfigurableOptionsProviderInterface
      */
-    private $configurableOptionsProvider;
+    private ConfigurableOptionsProviderInterface $configurableOptionsProvider;
+
+    /**
+     * @var SpecialPriceBulkResolver
+     */
+    private SpecialPriceBulkResolver $specialPriceBulkResolver;
+
+    /**
+     * @var array
+     */
+    private array $specialPriceMap = [];
 
     /**
      * @param Context $context
@@ -33,17 +44,19 @@ class FinalPriceBox extends \Magento\Catalog\Pricing\Render\FinalPriceBox
      * @param SalableResolverInterface $salableResolver
      * @param MinimalPriceCalculatorInterface $minimalPriceCalculator
      * @param ConfigurableOptionsProviderInterface $configurableOptionsProvider
+     * @param SpecialPriceBulkResolver $specialPriceBulkResolver
      * @param array $data
      */
     public function __construct(
-        Context $context,
-        SaleableInterface $saleableItem,
-        PriceInterface $price,
-        RendererPool $rendererPool,
-        SalableResolverInterface $salableResolver,
-        MinimalPriceCalculatorInterface $minimalPriceCalculator,
+        Context                              $context,
+        SaleableInterface                    $saleableItem,
+        PriceInterface                       $price,
+        RendererPool                         $rendererPool,
+        SalableResolverInterface             $salableResolver,
+        MinimalPriceCalculatorInterface      $minimalPriceCalculator,
         ConfigurableOptionsProviderInterface $configurableOptionsProvider,
-        array $data = []
+        SpecialPriceBulkResolver             $specialPriceBulkResolver,
+        array                                $data = []
     ) {
         parent::__construct(
             $context,
@@ -56,23 +69,40 @@ class FinalPriceBox extends \Magento\Catalog\Pricing\Render\FinalPriceBox
         );
 
         $this->configurableOptionsProvider = $configurableOptionsProvider;
+        $this->specialPriceBulkResolver = $specialPriceBulkResolver;
     }
 
     /**
      * Define if the special price should be shown
      *
      * @return bool
+     * @throws \Exception
      */
     public function hasSpecialPrice()
     {
-        $product = $this->getSaleableItem();
-        foreach ($this->configurableOptionsProvider->getProducts($product) as $subProduct) {
-            $regularPrice = $subProduct->getPriceInfo()->getPrice(RegularPrice::PRICE_CODE)->getValue();
-            $finalPrice = $subProduct->getPriceInfo()->getPrice(FinalPrice::PRICE_CODE)->getValue();
-            if ($finalPrice < $regularPrice) {
-                return true;
+        if ($this->isProductList()) {
+            if ($this->getData('product_list') === null) {
+                return false;
+            }
+
+            if (empty($this->specialPriceMap)) {
+                $this->specialPriceMap = $this->specialPriceBulkResolver->generateSpecialPriceMap(
+                    $this->saleableItem->getStoreId(),
+                    $this->getData('product_list')
+                );
+            }
+
+            return $this->specialPriceMap[$this->saleableItem->getId()];
+        } else {
+            $product = $this->getSaleableItem();
+            foreach ($this->configurableOptionsProvider->getProducts($product) as $subProduct) {
+                $regularPrice = $subProduct->getPriceInfo()->getPrice(RegularPrice::PRICE_CODE)->getValue();
+                $finalPrice = $subProduct->getPriceInfo()->getPrice(FinalPrice::PRICE_CODE)->getValue();
+                if ($finalPrice < $regularPrice) {
+                    return true;
+                }
             }
+            return false;
         }
-        return false;
     }
 }
diff --git a/vendor/magento/module-configurable-product/etc/di.xml b/vendor/magento/module-configurable-product/etc/di.xml
index 16e3aaafc9c..7ce4d50df81 100644
--- a/vendor/magento/module-configurable-product/etc/di.xml
+++ b/vendor/magento/module-configurable-product/etc/di.xml
@@ -283,4 +283,9 @@
     <type name="Magento\CatalogInventory\Model\ResourceModel\Stock\Item">
         <plugin name="updateStockChangedAuto" type="Magento\ConfigurableProduct\Model\Plugin\UpdateStockChangedAuto" />
     </type>
+    <type name="Magento\ConfigurableProduct\Pricing\Price\SpecialPriceBulkResolver">
+        <arguments>
+            <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Collection</argument>
+        </arguments>
+    </type>
 </config>
diff --git a/vendor/magento/module-configurable-product/view/base/templates/product/price/final_price.phtml b/vendor/magento/module-configurable-product/view/base/templates/product/price/final_price.phtml
index a6dc6c81998..c1238139d01 100644
--- a/vendor/magento/module-configurable-product/view/base/templates/product/price/final_price.phtml
+++ b/vendor/magento/module-configurable-product/view/base/templates/product/price/final_price.phtml
@@ -4,7 +4,7 @@
  * See COPYING.txt for license details.
  */
 
-/** @var \Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox$block */
+/** @var \Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox $block */
 /** @var \Magento\Framework\Pricing\Price\PriceInterface $priceModel */
 $priceModel = $block->getPriceType('regular_price');
 /** @var \Magento\Framework\Pricing\Price\PriceInterface $finalPriceModel */
@@ -23,24 +23,24 @@ $schema = ($block->getZone() == 'item_view') ? true : false;
 ?>
 </span>
 
-<?php if (!$block->isProductList() && $block->hasSpecialPrice()) : ?>
+<?php if ($block->hasSpecialPrice()): ?>
     <span class="old-price sly-old-price no-display">
         <?= /* @noEscape */ $block->renderAmount($priceModel->getAmount(), [
             'display_label'     => __('Regular Price'),
             'price_id'          => $block->getPriceId('old-price-' . $idSuffix),
             'price_type'        => 'oldPrice',
             'include_container' => true,
-            'skip_adjustments'  => true
+            'skip_adjustments'  => false
         ]); ?>
     </span>
 <?php endif; ?>
 
-<?php if ($block->showMinimalPrice()) : ?>
-    <?php if ($block->getUseLinkForAsLowAs()) :?>
+<?php if ($block->showMinimalPrice()): ?>
+    <?php if ($block->getUseLinkForAsLowAs()): ?>
         <a href="<?= $block->escapeUrl($block->getSaleableItem()->getProductUrl()) ?>" class="minimal-price-link">
             <?= /* @noEscape */ $block->renderAmountMinimal() ?>
         </a>
-    <?php else :?>
+    <?php else:?>
         <span class="minimal-price-link">
             <?= /* @noEscape */ $block->renderAmountMinimal() ?>
         </span>
