PrestaShop Database: Key Tables Every Store Owner Should Know
Why Understanding the Database Matters
PrestaShop stores everything — products, orders, customers, settings, translations, images, prices — in a MySQL database. While you can manage most things through the admin panel, understanding the database structure gives you superpowers. You can diagnose problems faster, perform bulk operations that would take hours through the UI, recover from errors that break the admin panel, and make informed decisions about optimization and scaling.
PrestaShop's database uses a prefix system (default ps_) for all table names. This prefix can be customized during installation, so your tables might use a different prefix. In this guide, we use the default ps_ prefix.
Product Tables
ps_product
The core product table. Contains one row per product with fundamental product data -
| Column | Purpose |
|---|---|
| id_product | Unique product identifier |
| id_category_default | Default category for the product |
| price | Base price (tax excluded) |
| wholesale_price | Cost/purchase price |
| reference | Product reference/SKU |
| ean13 | EAN-13 barcode |
| quantity | Stock quantity (legacy, see ps_stock_available) |
| active | Whether the product is enabled (1) or disabled (0) |
| date_add | Creation date |
| date_upd | Last modification date |
ps_product_lang
Contains language-specific product data - name, description, meta title, meta description, link_rewrite (URL slug). One row per product per language per shop.
-- Find products missing descriptions in a specific language
SELECT p.id_product, pl.name
FROM ps_product p
JOIN ps_product_lang pl ON p.id_product = pl.id_product
WHERE pl.id_lang = 1
AND (pl.description IS NULL OR pl.description = '');ps_product_shop
Multistore-specific product data. Contains price, active status, and visibility settings per shop. In single-store setups, this mirrors ps_product.
ps_stock_available
The actual stock tracking table. This is where PrestaShop reads stock quantities from (not ps_product.quantity, which is legacy).
-- Check stock for a specific product
SELECT * FROM ps_stock_available
WHERE id_product = 42 AND id_product_attribute = 0;ps_product_attribute
Product combinations/variants. Each row represents a specific combination of attributes (e.g., Size: L, Color: Blue). Contains price impact, weight impact, reference, and EAN for each combination.
ps_specific_price
Discounts and special prices. Handles percentage discounts, fixed-amount discounts, prices per customer group, date ranges, and quantity-based pricing.
Category Tables
ps_category
Category tree structure using nested sets (nleft, nright, level_depth). Key columns include id_parent, active, position, and date_add.
ps_category_lang
Language-specific category data - name, description, meta title, meta description, link_rewrite.
ps_category_product
Many-to-many relationship between products and categories. Each row links a product to a category with a position value for ordering.
-- Find all products in a specific category
SELECT p.id_product, pl.name, cp.position
FROM ps_category_product cp
JOIN ps_product p ON cp.id_product = p.id_product
JOIN ps_product_lang pl ON p.id_product = pl.id_product AND pl.id_lang = 1
WHERE cp.id_category = 5
ORDER BY cp.position;Order Tables
ps_orders
The most important commerce table. Each row is a completed order. Key columns -
| Column | Purpose |
|---|---|
| id_order | Unique order ID |
| reference | Order reference code (e.g., ABCDEF123) |
| id_customer | Customer who placed the order |
| id_cart | Cart that became this order |
| current_state | Current order status ID |
| payment | Payment method name |
| total_paid | Total amount paid |
| total_paid_tax_incl | Total with tax |
| total_products_wt | Products total with tax |
| total_shipping_tax_incl | Shipping cost with tax |
| date_add | Order date |
ps_order_detail
Individual line items within an order. Contains product_id, product_name, product_quantity, product_price, unit_price_tax_incl, and total_price_tax_incl.
-- Get order summary with line items
SELECT o.reference, o.date_add, o.total_paid_tax_incl,
od.product_name, od.product_quantity, od.unit_price_tax_incl
FROM ps_orders o
JOIN ps_order_detail od ON o.id_order = od.id_order
WHERE o.id_order = 12345;ps_order_state and ps_order_state_lang
Define order statuses (Awaiting payment, Payment accepted, Shipped, Delivered, etc.) and their translated names.
ps_order_history
A log of all status changes for each order, with timestamps. Useful for tracking order processing speed.
Customer Tables
ps_customer
Customer accounts. Key columns include email, passwd (hashed), firstname, lastname, id_default_group, newsletter (subscription status), active, and date_add.
-- Find customers who registered but never ordered
SELECT c.id_customer, c.email, c.firstname, c.lastname, c.date_add
FROM ps_customer c
LEFT JOIN ps_orders o ON c.id_customer = o.id_customer
WHERE o.id_order IS NULL
AND c.active = 1;ps_address
Customer addresses. Linked to customers via id_customer. Contains company, firstname, lastname, address1, address2, postcode, city, id_country, id_state, phone, phone_mobile.
ps_guest
Tracks anonymous visitors before they register or log in. Linked to carts for guest checkout scenarios.
Cart Tables
ps_cart
Shopping carts. Contains id_customer, id_address_delivery, id_address_invoice, id_currency, id_lang, and date_add. Not every cart becomes an order — abandoned carts remain here.
ps_cart_product
Products in each cart, with quantities and selected attributes/combinations.
-- Find abandoned carts from the last 7 days with products
SELECT c.id_cart, cu.email, c.date_add,
GROUP_CONCAT(pl.name SEPARATOR ', ') AS products
FROM ps_cart c
JOIN ps_customer cu ON c.id_customer = cu.id_customer
JOIN ps_cart_product cp ON c.id_cart = cp.id_cart
JOIN ps_product_lang pl ON cp.id_product = pl.id_product AND pl.id_lang = 1
LEFT JOIN ps_orders o ON c.id_cart = o.id_cart
WHERE o.id_order IS NULL
AND c.date_add > DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY c.id_cart;Configuration Tables
ps_configuration
PrestaShop's key-value store for all settings. Every option you configure in the back office is stored here. Key columns are name (setting key) and value (setting value).
-- Check your shop's current settings
SELECT name, value FROM ps_configuration
WHERE name IN ('PS_SHOP_DOMAIN', 'PS_SHOP_DOMAIN_SSL',
'PS_SSL_ENABLED', 'PS_SHOP_ENABLE', 'PS_LANG_DEFAULT');ps_configuration_lang
Language-specific configuration values. Some settings (like email templates) have different values per language.
Module and Hook Tables
ps_module
List of all installed modules with their version numbers. One row per module.
ps_hook
All available hooks in the system. Hooks are extension points where modules can inject content or behavior.
ps_hook_module
Maps which modules are attached to which hooks, with their display position. This controls the execution order when multiple modules use the same hook.
-- Find all modules attached to a specific hook
SELECT h.name AS hook_name, m.name AS module_name, hm.position
FROM ps_hook_module hm
JOIN ps_hook h ON hm.id_hook = h.id_hook
JOIN ps_module m ON hm.id_module = m.id_module
WHERE h.name = 'displayHeader'
ORDER BY hm.position;SEO and URL Tables
ps_meta and ps_meta_lang
URL patterns and meta information for controller pages (index, category, product, cms, etc.).
ps_shop_url
Maps domains and URIs to shops. Critical for multistore setups and should never be modified carelessly.
Image Tables
ps_image
Product images with position and cover flag. Links to ps_product via id_product.
ps_image_lang
Language-specific image alt text and legend.
Common Database Operations
Bulk Price Updates
-- Increase all prices by 10%
UPDATE ps_product SET price = price * 1.10;
UPDATE ps_product_shop SET price = price * 1.10;Bulk Enable/Disable Products
-- Disable all out-of-stock products
UPDATE ps_product p
JOIN ps_stock_available sa ON p.id_product = sa.id_product
AND sa.id_product_attribute = 0
SET p.active = 0
WHERE sa.quantity <= 0;Find and Fix Orphaned Data
-- Find products that exist but have no language data
SELECT p.id_product FROM ps_product p
LEFT JOIN ps_product_lang pl ON p.id_product = pl.id_product
WHERE pl.id_product IS NULL;Database Safety Rules
- Always back up before modifying data
- Never modify ps_shop_url directly — use the admin panel
- Never change employee passwords directly — use the password reset feature
- Never drop tables created by modules — uninstall the module instead
- Always use transactions for multi-table updates
- Test queries with SELECT before running UPDATE or DELETE
For more details, read our guides: Database Cleanup: Why Your PrestaShop Store Gets Slower Over Time and Performance Tuning Your PrestaShop Store: From Database Queries to Full Page Cache.
Was this answer helpful?
Still have questions?
Can't find what you're looking for? Send us your question and we'll get back to you quickly.